shape.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use freetype as ft;
  19. use harfbuzz_sys::{
  20. freetype::hb_ft_font_create_referenced, hb_buffer_add_utf8, hb_buffer_create,
  21. hb_buffer_destroy, hb_buffer_get_glyph_infos, hb_buffer_get_glyph_positions,
  22. hb_buffer_guess_segment_properties, hb_buffer_set_cluster_level, hb_buffer_set_content_type,
  23. hb_buffer_t, hb_font_destroy, hb_font_t, hb_glyph_info_t, hb_glyph_position_t, hb_shape,
  24. HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES, HB_BUFFER_CONTENT_TYPE_UNICODE,
  25. };
  26. use std::{iter::Peekable, os, vec::IntoIter};
  27. type FreetypeFace = ft::Face<&'static [u8]>;
  28. struct HarfBuzzInfo<'a> {
  29. info: &'a hb_glyph_info_t,
  30. pos: &'a hb_glyph_position_t,
  31. }
  32. struct HarfBuzzIter<'a> {
  33. hb_font: *mut hb_font_t,
  34. buf: *mut hb_buffer_t,
  35. infos_iter: std::slice::Iter<'a, hb_glyph_info_t>,
  36. pos_iter: std::slice::Iter<'a, hb_glyph_position_t>,
  37. }
  38. impl<'a> Iterator for HarfBuzzIter<'a> {
  39. type Item = HarfBuzzInfo<'a>;
  40. fn next(&mut self) -> Option<Self::Item> {
  41. let info = self.infos_iter.next()?;
  42. let pos = self.pos_iter.next()?;
  43. Some(HarfBuzzInfo { info, pos })
  44. }
  45. }
  46. impl<'a> Drop for HarfBuzzIter<'a> {
  47. fn drop(&mut self) {
  48. unsafe {
  49. hb_buffer_destroy(self.buf);
  50. hb_font_destroy(self.hb_font);
  51. }
  52. }
  53. }
  54. pub(super) fn set_face_size(face: &mut FreetypeFace, size: f32) {
  55. if face.has_fixed_sizes() {
  56. //debug!(target: "text", "fixed sizes");
  57. // emojis required a fixed size
  58. //face.set_char_size(109 * 64, 0, 72, 72).unwrap();
  59. face.select_size(0).unwrap();
  60. } else {
  61. //debug!(target: "text", "set char size");
  62. face.set_char_size(size as isize * 64, 0, 96, 96).unwrap();
  63. }
  64. }
  65. fn harfbuzz_shape<'a>(face: &mut FreetypeFace, text: &str) -> HarfBuzzIter<'a> {
  66. let utf8_ptr = text.as_ptr() as *const _;
  67. // https://harfbuzz.github.io/a-simple-shaping-example.html
  68. let (hb_font, buf, glyph_infos, glyph_pos) = unsafe {
  69. let ft_face_ptr: freetype::freetype_sys::FT_Face = face.raw_mut();
  70. let hb_font = hb_ft_font_create_referenced(ft_face_ptr);
  71. let buf = hb_buffer_create();
  72. hb_buffer_set_content_type(buf, HB_BUFFER_CONTENT_TYPE_UNICODE);
  73. hb_buffer_set_cluster_level(buf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES);
  74. hb_buffer_add_utf8(
  75. buf,
  76. utf8_ptr,
  77. text.len() as os::raw::c_int,
  78. 0 as os::raw::c_uint,
  79. text.len() as os::raw::c_int,
  80. );
  81. hb_buffer_guess_segment_properties(buf);
  82. hb_shape(hb_font, buf, std::ptr::null(), 0 as os::raw::c_uint);
  83. let mut length: u32 = 0;
  84. let glyph_infos = hb_buffer_get_glyph_infos(buf, &mut length as *mut u32);
  85. let glyph_infos: &[hb_glyph_info_t] =
  86. std::slice::from_raw_parts(glyph_infos as *const _, length as usize);
  87. let glyph_pos = hb_buffer_get_glyph_positions(buf, &mut length as *mut u32);
  88. let glyph_pos: &[hb_glyph_position_t] =
  89. std::slice::from_raw_parts(glyph_pos as *const _, length as usize);
  90. (hb_font, buf, glyph_infos, glyph_pos)
  91. };
  92. let infos_iter = glyph_infos.iter();
  93. let pos_iter = glyph_pos.iter();
  94. HarfBuzzIter { hb_font, buf, infos_iter, pos_iter }
  95. }
  96. pub(super) struct GlyphInfo {
  97. pub face_idx: usize,
  98. pub id: u32,
  99. pub cluster_start: usize,
  100. pub cluster_end: usize,
  101. pub x_offset: i32,
  102. pub y_offset: i32,
  103. pub x_advance: i32,
  104. pub y_advance: i32,
  105. }
  106. impl GlyphInfo {
  107. pub fn substr<'a>(&self, text: &'a str) -> &'a str {
  108. // RTL
  109. let start = std::cmp::min(self.cluster_start, self.cluster_end);
  110. let end = std::cmp::max(self.cluster_start, self.cluster_end);
  111. &text[start..end]
  112. }
  113. }
  114. struct ShapedGlyphs {
  115. glyphs: Vec<GlyphInfo>,
  116. }
  117. impl ShapedGlyphs {
  118. fn new(glyphs: Vec<GlyphInfo>) -> Self {
  119. Self { glyphs }
  120. }
  121. fn has_zero(&self) -> bool {
  122. self.glyphs.iter().any(|g| g.id == 0)
  123. }
  124. fn fill_zeros(&mut self, fallback: Vec<GlyphInfo>) {
  125. let mut primary_iter = std::mem::take(&mut self.glyphs).into_iter().peekable();
  126. let mut fallback_iter = fallback.into_iter().peekable();
  127. assert!(self.glyphs.is_empty());
  128. while let Some(primary_glyph) = primary_iter.next() {
  129. if primary_glyph.id != 0 {
  130. Self::consume(&mut fallback_iter, primary_glyph.cluster_start);
  131. self.glyphs.push(primary_glyph);
  132. continue
  133. }
  134. let mut fallbacks = Self::consume(&mut fallback_iter, primary_glyph.cluster_start);
  135. let Some(last_fallback) = fallbacks.last() else { continue };
  136. let cluster_end = last_fallback.cluster_end;
  137. self.glyphs.append(&mut fallbacks);
  138. Self::drop_replaced(&mut primary_iter, cluster_end);
  139. }
  140. }
  141. fn consume(iter: &mut Peekable<IntoIter<GlyphInfo>>, cluster_bound: usize) -> Vec<GlyphInfo> {
  142. let mut consumed = vec![];
  143. while let Some(glyph) = iter.peek() {
  144. if glyph.cluster_start > cluster_bound {
  145. break
  146. }
  147. let glyph = iter.next().unwrap();
  148. consumed.push(glyph);
  149. }
  150. consumed
  151. }
  152. fn drop_replaced(iter: &mut Peekable<IntoIter<GlyphInfo>>, cluster_end: usize) {
  153. while let Some(glyph) = iter.peek() {
  154. if glyph.cluster_start >= cluster_end {
  155. break
  156. }
  157. let _ = iter.next();
  158. }
  159. }
  160. }
  161. /*
  162. fn print_glyphs(ctx: &str, glyphs: &Vec<GlyphInfo>, indent: usize) {
  163. let ws = " ".repeat(2 * indent);
  164. println!("{ws}{} ------------------", ctx);
  165. for (i, glyph) in glyphs.iter().enumerate() {
  166. println!(
  167. "{ws}{i}: {}/{} [{}, {}]",
  168. glyph.face_idx, glyph.id, glyph.cluster_start, glyph.cluster_end
  169. );
  170. }
  171. println!("{ws}---------------------");
  172. }
  173. */
  174. fn face_shape(face: &mut FreetypeFace, text: &str, face_idx: usize) -> Vec<GlyphInfo> {
  175. let mut glyphs: Vec<GlyphInfo> = vec![];
  176. for (i, hbinf) in harfbuzz_shape(face, text).enumerate() {
  177. let glyph_id = hbinf.info.codepoint as u32;
  178. // Index within this substr
  179. let cluster = hbinf.info.cluster as usize;
  180. //println!(" {i}: glyph_id = {glyph_id}, cluster = {cluster}");
  181. if i != 0 {
  182. glyphs.last_mut().unwrap().cluster_end = cluster;
  183. }
  184. glyphs.push(GlyphInfo {
  185. face_idx,
  186. id: glyph_id,
  187. cluster_start: cluster,
  188. cluster_end: 0,
  189. x_offset: hbinf.pos.x_offset,
  190. y_offset: hbinf.pos.y_offset,
  191. x_advance: hbinf.pos.x_advance,
  192. y_advance: hbinf.pos.y_advance,
  193. });
  194. }
  195. if let Some(last) = glyphs.last_mut() {
  196. last.cluster_end = text.len();
  197. }
  198. glyphs
  199. }
  200. /// Shape text using fallback fonts. We shape it using the primary font, then go down through
  201. /// the list of fallbacks. For every zero we encounter, take the remaining text on that line
  202. /// and try to shape it. Then replace that glyph + any others in the cluster with the new one.
  203. /// [More info](https://zachbayl.in/blog/font_fallback_revery/)
  204. pub(super) fn shape(faces: &mut Vec<FreetypeFace>, text: &str) -> Vec<GlyphInfo> {
  205. let glyphs = face_shape(&mut faces[0], text, 0);
  206. let mut shaped = ShapedGlyphs::new(glyphs);
  207. // Go down successively in our fallbacks
  208. for face_idx in 1..faces.len() {
  209. if !shaped.has_zero() {
  210. break
  211. }
  212. let glyphs = face_shape(&mut faces[face_idx], text, face_idx);
  213. shaped.fill_zeros(glyphs);
  214. }
  215. shaped.glyphs
  216. }
  217. #[cfg(test)]
  218. mod tests {
  219. use super::*;
  220. fn load_faces() -> Vec<FreetypeFace> {
  221. let ftlib = freetype::Library::init().unwrap();
  222. let mut faces = vec![];
  223. let font_data = include_bytes!("../../ibm-plex-mono-regular.otf") as &[u8];
  224. let face = ftlib.new_memory_face2(font_data, 0).unwrap();
  225. faces.push(face);
  226. let font_data = include_bytes!("../../NotoColorEmoji.ttf") as &[u8];
  227. let face = ftlib.new_memory_face2(font_data, 0).unwrap();
  228. faces.push(face);
  229. //let font_data = include_bytes!("../noto-serif-cjk-jp-regular.otf") as &[u8];
  230. //let face = ftlib.new_memory_face2(font_data, 0).unwrap();
  231. //faces.push(face);
  232. faces
  233. }
  234. #[test]
  235. fn simple_shape_test() {
  236. let mut faces = load_faces();
  237. let text = "\u{01f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f}";
  238. let glyphs = shape(&mut faces, text);
  239. assert_eq!(glyphs.len(), 1);
  240. assert_eq!(glyphs[0].face_idx, 1);
  241. assert_eq!(glyphs[0].id, 1895);
  242. assert_eq!(glyphs[0].cluster_start, 0);
  243. assert_eq!(glyphs[0].cluster_end, 16);
  244. }
  245. #[test]
  246. fn simple_double_shape_test() {
  247. let mut faces = load_faces();
  248. let text =
  249. "\u{01f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f}\u{01f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f}";
  250. let glyphs = shape(&mut faces, text);
  251. assert_eq!(glyphs.len(), 2);
  252. assert_eq!(glyphs[0].face_idx, 1);
  253. assert_eq!(glyphs[0].id, 1895);
  254. assert_eq!(glyphs[0].cluster_start, 0);
  255. assert_eq!(glyphs[0].cluster_end, 16);
  256. assert_eq!(glyphs[1].face_idx, 1);
  257. assert_eq!(glyphs[1].id, 1895);
  258. assert_eq!(glyphs[1].cluster_start, 16);
  259. assert_eq!(glyphs[1].cluster_end, 32);
  260. }
  261. #[test]
  262. fn mixed_shape_test() {
  263. //let text = "日本語";
  264. //let text = "hel 日本語\u{01f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f} ally";
  265. let mut faces = load_faces();
  266. let text = "hel \u{01f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f} 123 X\u{01f44d}\u{01f3fe}X br";
  267. let glyphs = shape(&mut faces, text);
  268. assert_eq!(glyphs[0].face_idx, 0);
  269. assert_eq!(glyphs[0].id, 11);
  270. assert_eq!(glyphs[0].cluster_start, 0);
  271. assert_eq!(glyphs[0].cluster_end, 1);
  272. assert_eq!(glyphs[1].face_idx, 0);
  273. assert_eq!(glyphs[1].id, 6);
  274. assert_eq!(glyphs[1].cluster_start, 1);
  275. assert_eq!(glyphs[1].cluster_end, 2);
  276. assert_eq!(glyphs[1].cluster_start, glyphs[0].cluster_end);
  277. assert_eq!(glyphs[2].face_idx, 0);
  278. assert_eq!(glyphs[2].id, 15);
  279. assert_eq!(glyphs[2].cluster_start, 2);
  280. assert_eq!(glyphs[2].cluster_end, 3);
  281. assert_eq!(glyphs[2].cluster_start, glyphs[1].cluster_end);
  282. assert_eq!(glyphs[3].face_idx, 0);
  283. assert_eq!(glyphs[3].id, 1099);
  284. assert_eq!(glyphs[3].cluster_start, 3);
  285. assert_eq!(glyphs[3].cluster_end, 4);
  286. assert_eq!(glyphs[3].cluster_start, glyphs[2].cluster_end);
  287. assert_eq!(glyphs[4].face_idx, 1);
  288. assert_eq!(glyphs[4].id, 1895);
  289. assert_eq!(glyphs[4].cluster_start, 4);
  290. assert_eq!(glyphs[4].cluster_end, 20);
  291. assert_eq!(glyphs[4].cluster_start, glyphs[3].cluster_end);
  292. assert_eq!(glyphs[5].face_idx, 0);
  293. assert_eq!(glyphs[5].id, 1099);
  294. assert_eq!(glyphs[5].cluster_start, 20);
  295. assert_eq!(glyphs[5].cluster_end, 21);
  296. assert_eq!(glyphs[5].cluster_start, glyphs[4].cluster_end);
  297. assert_eq!(glyphs[6].face_idx, 0);
  298. assert_eq!(glyphs[6].id, 59);
  299. assert_eq!(glyphs[6].cluster_start, 21);
  300. assert_eq!(glyphs[6].cluster_end, 22);
  301. assert_eq!(glyphs[6].cluster_start, glyphs[5].cluster_end);
  302. assert_eq!(glyphs[7].face_idx, 0);
  303. assert_eq!(glyphs[7].id, 60);
  304. assert_eq!(glyphs[7].cluster_start, 22);
  305. assert_eq!(glyphs[7].cluster_end, 23);
  306. assert_eq!(glyphs[7].cluster_start, glyphs[6].cluster_end);
  307. assert_eq!(glyphs[8].face_idx, 0);
  308. assert_eq!(glyphs[8].id, 61);
  309. assert_eq!(glyphs[8].cluster_start, 23);
  310. assert_eq!(glyphs[8].cluster_end, 24);
  311. assert_eq!(glyphs[8].cluster_start, glyphs[7].cluster_end);
  312. assert_eq!(glyphs[9].face_idx, 0);
  313. assert_eq!(glyphs[9].id, 1099);
  314. assert_eq!(glyphs[9].cluster_start, 24);
  315. assert_eq!(glyphs[9].cluster_end, 25);
  316. assert_eq!(glyphs[9].cluster_start, glyphs[8].cluster_end);
  317. assert_eq!(glyphs[10].face_idx, 0);
  318. assert_eq!(glyphs[10].id, 53);
  319. assert_eq!(glyphs[10].cluster_start, 25);
  320. assert_eq!(glyphs[10].cluster_end, 26);
  321. assert_eq!(glyphs[10].cluster_start, glyphs[9].cluster_end);
  322. assert_eq!(glyphs[11].face_idx, 1);
  323. assert_eq!(glyphs[11].id, 1955);
  324. assert_eq!(glyphs[11].cluster_start, 26);
  325. assert_eq!(glyphs[11].cluster_end, 34);
  326. assert_eq!(glyphs[11].cluster_start, glyphs[10].cluster_end);
  327. assert_eq!(glyphs[12].face_idx, 0);
  328. assert_eq!(glyphs[12].id, 53);
  329. assert_eq!(glyphs[12].cluster_start, 34);
  330. assert_eq!(glyphs[12].cluster_end, 35);
  331. assert_eq!(glyphs[12].cluster_start, glyphs[11].cluster_end);
  332. assert_eq!(glyphs[13].face_idx, 0);
  333. assert_eq!(glyphs[13].id, 1099);
  334. assert_eq!(glyphs[13].cluster_start, 35);
  335. assert_eq!(glyphs[13].cluster_end, 36);
  336. assert_eq!(glyphs[13].cluster_start, glyphs[12].cluster_end);
  337. assert_eq!(glyphs[14].face_idx, 0);
  338. assert_eq!(glyphs[14].id, 3);
  339. assert_eq!(glyphs[14].cluster_start, 36);
  340. assert_eq!(glyphs[14].cluster_end, 37);
  341. assert_eq!(glyphs[14].cluster_start, glyphs[13].cluster_end);
  342. assert_eq!(glyphs[15].face_idx, 0);
  343. assert_eq!(glyphs[15].id, 21);
  344. assert_eq!(glyphs[15].cluster_start, 37);
  345. assert_eq!(glyphs[15].cluster_end, 38);
  346. assert_eq!(glyphs[15].cluster_start, glyphs[14].cluster_end);
  347. }
  348. #[test]
  349. fn hb_shape_custom_emoji() {
  350. let ftlib = ft::Library::init().unwrap();
  351. let font_data = include_bytes!("../../darkirc-emoji-svg.ttf") as &[u8];
  352. let mut face = ftlib.new_memory_face2(font_data, 0).unwrap();
  353. let text = "\u{f0001}";
  354. for (i, hbinf) in harfbuzz_shape(&mut face, text).enumerate() {
  355. let glyph_id = hbinf.info.codepoint as u32;
  356. // Index within this substr
  357. let cluster = hbinf.info.cluster as usize;
  358. //println!(" {i}: glyph_id = {glyph_id}, cluster = {cluster}");
  359. }
  360. }
  361. #[test]
  362. fn custom_emoji() {
  363. let ftlib = ft::Library::init().unwrap();
  364. let font_data = include_bytes!("../../darkirc-emoji-svg.ttf") as &[u8];
  365. let face = ftlib.new_memory_face2(font_data, 0).unwrap();
  366. let mut faces = vec![face];
  367. let text = "\u{f0001}";
  368. let glyphs = shape(&mut faces, text);
  369. //print_glyphs("", &glyphs);
  370. }
  371. /*
  372. #[test]
  373. fn weird_stuff() {
  374. let mut faces = load_faces();
  375. //let text = "( \u{361}° \u{35c}ʖ \u{361}°)";
  376. let text = "\u{35c}ʖ \u{361}a";
  377. let glyphs = shape(&mut faces, text);
  378. }
  379. */
  380. }