shape.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 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::os;
  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. &text[self.cluster_start..self.cluster_end]
  109. }
  110. }
  111. struct ShapedGlyphs {
  112. glyphs: Vec<GlyphInfo>,
  113. }
  114. impl ShapedGlyphs {
  115. fn new(glyphs: Vec<GlyphInfo>) -> Self {
  116. Self { glyphs }
  117. }
  118. fn surgery(&mut self, idx: usize, glyphs: Vec<GlyphInfo>) {
  119. let tail = self.glyphs.split_off(idx);
  120. let mut tail_iter = tail.into_iter().peekable();
  121. for glyph in glyphs {
  122. // We have a glyph. Lets consume tail.
  123. // We continue while the glyphs are before this glyph's end.
  124. while let Some(tail_glyph) = tail_iter.peek() &&
  125. tail_glyph.cluster_start < glyph.cluster_end
  126. {
  127. tail_iter.next();
  128. }
  129. self.glyphs.push(glyph);
  130. // Only continue while the tail starts with 0
  131. if let Some(tail_glyph) = tail_iter.peek() {
  132. if tail_glyph.id != 0 {
  133. break
  134. }
  135. }
  136. }
  137. self.glyphs.extend(tail_iter);
  138. }
  139. fn scan_zero(&self, start_idx: usize) -> Option<(usize, usize)> {
  140. let mut glyphs_iter = self.glyphs.iter().enumerate();
  141. if glyphs_iter.advance_by(start_idx).is_err() {
  142. return None
  143. }
  144. for (i, glyph) in glyphs_iter {
  145. if glyph.id == 0 {
  146. return Some((i, glyph.cluster_start))
  147. }
  148. }
  149. None
  150. }
  151. }
  152. /// Count the number of leading zeros
  153. fn count_leading_null_glyphs(glyphs: &Vec<GlyphInfo>) -> usize {
  154. let mut cnt = 0;
  155. for glyph in glyphs {
  156. if glyph.id != 0 {
  157. break
  158. }
  159. cnt += 1;
  160. }
  161. cnt
  162. }
  163. /*
  164. fn print_glyphs(ctx: &str, glyphs: &Vec<GlyphInfo>) {
  165. println!("{} ------------------", ctx);
  166. for (i, glyph) in glyphs.iter().enumerate() {
  167. println!(
  168. "{i}: {}/{} [{}, {}]",
  169. glyph.face_idx, glyph.id, glyph.cluster_start, glyph.cluster_end
  170. );
  171. }
  172. println!("---------------------");
  173. }
  174. */
  175. fn face_shape(face: &mut FreetypeFace, text: &str, off: usize, face_idx: usize) -> Vec<GlyphInfo> {
  176. let mut glyphs: Vec<GlyphInfo> = vec![];
  177. for (i, hbinf) in harfbuzz_shape(face, text).enumerate() {
  178. let glyph_id = hbinf.info.codepoint as u32;
  179. // Index within this substr
  180. let cluster = hbinf.info.cluster as usize;
  181. //println!(" {i}: glyph_id = {glyph_id}, cluster = {cluster}");
  182. let remain_text = &text[cluster..];
  183. //println!(" remain_text='{remain_text}'");
  184. if i != 0 {
  185. glyphs.last_mut().unwrap().cluster_end = cluster + off;
  186. }
  187. glyphs.push(GlyphInfo {
  188. face_idx,
  189. id: glyph_id,
  190. cluster_start: cluster + off,
  191. cluster_end: 0,
  192. x_offset: hbinf.pos.x_offset,
  193. y_offset: hbinf.pos.y_offset,
  194. x_advance: hbinf.pos.x_advance,
  195. y_advance: hbinf.pos.y_advance,
  196. });
  197. }
  198. if let Some(last) = glyphs.last_mut() {
  199. last.cluster_end = text.len() + off;
  200. }
  201. glyphs
  202. }
  203. /// Shape text using fallback fonts. We shape it using the primary font, then go down through
  204. /// the list of fallbacks. For every zero we encounter, take the remaining text on that line
  205. /// and try to shape it. Then replace that glyph + any others in the cluster with the new one.
  206. /// [More info](https://zachbayl.in/blog/font_fallback_revery/)
  207. pub(super) fn shape(faces: &mut Vec<FreetypeFace>, text: &str) -> Vec<GlyphInfo> {
  208. let glyphs = face_shape(&mut faces[0], text, 0, 0);
  209. let mut shaped = ShapedGlyphs::new(glyphs);
  210. // Go down successively in our fallbacks
  211. for face_idx in 1..faces.len() {
  212. // We attempt to replace each zero once. This idx keeps track so we don't
  213. // keep repeating zeros we already tried to replace.
  214. let mut last_idx = 0;
  215. // Find the next zero
  216. while let Some((off, cluster_start)) = shaped.scan_zero(last_idx) {
  217. let remain_text = &text[cluster_start..];
  218. let glyphs = face_shape(&mut faces[face_idx], remain_text, cluster_start, face_idx);
  219. // We weren't successful shaping with this fallback font, so skip over these glyphs.
  220. let leading_zeros = count_leading_null_glyphs(&glyphs);
  221. last_idx = off + leading_zeros;
  222. // Perform bottom surgery
  223. if leading_zeros == 0 {
  224. shaped.surgery(off, glyphs);
  225. }
  226. }
  227. }
  228. shaped.glyphs
  229. }
  230. #[cfg(test)]
  231. mod tests {
  232. use super::*;
  233. fn load_faces() -> Vec<FreetypeFace> {
  234. let ftlib = freetype::Library::init().unwrap();
  235. let mut faces = vec![];
  236. let font_data = include_bytes!("../../ibm-plex-mono-regular.otf") as &[u8];
  237. let face = ftlib.new_memory_face2(font_data, 0).unwrap();
  238. faces.push(face);
  239. let font_data = include_bytes!("../../NotoColorEmoji.ttf") as &[u8];
  240. let face = ftlib.new_memory_face2(font_data, 0).unwrap();
  241. faces.push(face);
  242. //let font_data = include_bytes!("../noto-serif-cjk-jp-regular.otf") as &[u8];
  243. //let face = ftlib.new_memory_face2(font_data, 0).unwrap();
  244. //faces.push(face);
  245. faces
  246. }
  247. #[test]
  248. fn simple_shape_test() {
  249. let mut faces = load_faces();
  250. let text = "\u{01f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f}";
  251. let glyphs = shape(&mut faces, text);
  252. assert_eq!(glyphs.len(), 1);
  253. assert_eq!(glyphs[0].face_idx, 1);
  254. assert_eq!(glyphs[0].id, 1895);
  255. assert_eq!(glyphs[0].cluster_start, 0);
  256. assert_eq!(glyphs[0].cluster_end, 16);
  257. }
  258. #[test]
  259. fn simple_double_shape_test() {
  260. let mut faces = load_faces();
  261. let text =
  262. "\u{01f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f}\u{01f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f}";
  263. let glyphs = shape(&mut faces, text);
  264. assert_eq!(glyphs.len(), 2);
  265. assert_eq!(glyphs[0].face_idx, 1);
  266. assert_eq!(glyphs[0].id, 1895);
  267. assert_eq!(glyphs[0].cluster_start, 0);
  268. assert_eq!(glyphs[0].cluster_end, 16);
  269. assert_eq!(glyphs[1].face_idx, 1);
  270. assert_eq!(glyphs[1].id, 1895);
  271. assert_eq!(glyphs[1].cluster_start, 16);
  272. assert_eq!(glyphs[1].cluster_end, 32);
  273. }
  274. #[test]
  275. fn mixed_shape_test() {
  276. //let text = "日本語";
  277. //let text = "hel 日本語\u{01f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f} ally";
  278. let mut faces = load_faces();
  279. let text = "hel \u{01f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f} 123 X\u{01f44d}\u{01f3fe}X br";
  280. let glyphs = shape(&mut faces, text);
  281. assert_eq!(glyphs[0].face_idx, 0);
  282. assert_eq!(glyphs[0].id, 11);
  283. assert_eq!(glyphs[0].cluster_start, 0);
  284. assert_eq!(glyphs[0].cluster_end, 1);
  285. assert_eq!(glyphs[1].face_idx, 0);
  286. assert_eq!(glyphs[1].id, 6);
  287. assert_eq!(glyphs[1].cluster_start, 1);
  288. assert_eq!(glyphs[1].cluster_end, 2);
  289. assert_eq!(glyphs[1].cluster_start, glyphs[0].cluster_end);
  290. assert_eq!(glyphs[2].face_idx, 0);
  291. assert_eq!(glyphs[2].id, 15);
  292. assert_eq!(glyphs[2].cluster_start, 2);
  293. assert_eq!(glyphs[2].cluster_end, 3);
  294. assert_eq!(glyphs[2].cluster_start, glyphs[1].cluster_end);
  295. assert_eq!(glyphs[3].face_idx, 0);
  296. assert_eq!(glyphs[3].id, 1099);
  297. assert_eq!(glyphs[3].cluster_start, 3);
  298. assert_eq!(glyphs[3].cluster_end, 4);
  299. assert_eq!(glyphs[3].cluster_start, glyphs[2].cluster_end);
  300. assert_eq!(glyphs[4].face_idx, 1);
  301. assert_eq!(glyphs[4].id, 1895);
  302. assert_eq!(glyphs[4].cluster_start, 4);
  303. assert_eq!(glyphs[4].cluster_end, 20);
  304. assert_eq!(glyphs[4].cluster_start, glyphs[3].cluster_end);
  305. assert_eq!(glyphs[5].face_idx, 0);
  306. assert_eq!(glyphs[5].id, 1099);
  307. assert_eq!(glyphs[5].cluster_start, 20);
  308. assert_eq!(glyphs[5].cluster_end, 21);
  309. assert_eq!(glyphs[5].cluster_start, glyphs[4].cluster_end);
  310. assert_eq!(glyphs[6].face_idx, 0);
  311. assert_eq!(glyphs[6].id, 59);
  312. assert_eq!(glyphs[6].cluster_start, 21);
  313. assert_eq!(glyphs[6].cluster_end, 22);
  314. assert_eq!(glyphs[6].cluster_start, glyphs[5].cluster_end);
  315. assert_eq!(glyphs[7].face_idx, 0);
  316. assert_eq!(glyphs[7].id, 60);
  317. assert_eq!(glyphs[7].cluster_start, 22);
  318. assert_eq!(glyphs[7].cluster_end, 23);
  319. assert_eq!(glyphs[7].cluster_start, glyphs[6].cluster_end);
  320. assert_eq!(glyphs[8].face_idx, 0);
  321. assert_eq!(glyphs[8].id, 61);
  322. assert_eq!(glyphs[8].cluster_start, 23);
  323. assert_eq!(glyphs[8].cluster_end, 24);
  324. assert_eq!(glyphs[8].cluster_start, glyphs[7].cluster_end);
  325. assert_eq!(glyphs[9].face_idx, 0);
  326. assert_eq!(glyphs[9].id, 1099);
  327. assert_eq!(glyphs[9].cluster_start, 24);
  328. assert_eq!(glyphs[9].cluster_end, 25);
  329. assert_eq!(glyphs[9].cluster_start, glyphs[8].cluster_end);
  330. assert_eq!(glyphs[10].face_idx, 0);
  331. assert_eq!(glyphs[10].id, 53);
  332. assert_eq!(glyphs[10].cluster_start, 25);
  333. assert_eq!(glyphs[10].cluster_end, 26);
  334. assert_eq!(glyphs[10].cluster_start, glyphs[9].cluster_end);
  335. assert_eq!(glyphs[11].face_idx, 1);
  336. assert_eq!(glyphs[11].id, 1955);
  337. assert_eq!(glyphs[11].cluster_start, 26);
  338. assert_eq!(glyphs[11].cluster_end, 34);
  339. assert_eq!(glyphs[11].cluster_start, glyphs[10].cluster_end);
  340. assert_eq!(glyphs[12].face_idx, 0);
  341. assert_eq!(glyphs[12].id, 53);
  342. assert_eq!(glyphs[12].cluster_start, 34);
  343. assert_eq!(glyphs[12].cluster_end, 35);
  344. assert_eq!(glyphs[12].cluster_start, glyphs[11].cluster_end);
  345. assert_eq!(glyphs[13].face_idx, 0);
  346. assert_eq!(glyphs[13].id, 1099);
  347. assert_eq!(glyphs[13].cluster_start, 35);
  348. assert_eq!(glyphs[13].cluster_end, 36);
  349. assert_eq!(glyphs[13].cluster_start, glyphs[12].cluster_end);
  350. assert_eq!(glyphs[14].face_idx, 0);
  351. assert_eq!(glyphs[14].id, 3);
  352. assert_eq!(glyphs[14].cluster_start, 36);
  353. assert_eq!(glyphs[14].cluster_end, 37);
  354. assert_eq!(glyphs[14].cluster_start, glyphs[13].cluster_end);
  355. assert_eq!(glyphs[15].face_idx, 0);
  356. assert_eq!(glyphs[15].id, 21);
  357. assert_eq!(glyphs[15].cluster_start, 37);
  358. assert_eq!(glyphs[15].cluster_end, 38);
  359. assert_eq!(glyphs[15].cluster_start, glyphs[14].cluster_end);
  360. }
  361. #[test]
  362. fn hb_shape_custom_emoji() {
  363. let ftlib = ft::Library::init().unwrap();
  364. let font_data = include_bytes!("../../darkirc-emoji-svg.ttf") as &[u8];
  365. let mut face = ftlib.new_memory_face2(font_data, 0).unwrap();
  366. let text = "\u{f0001}";
  367. for (i, hbinf) in harfbuzz_shape(&mut face, text).enumerate() {
  368. let glyph_id = hbinf.info.codepoint as u32;
  369. // Index within this substr
  370. let cluster = hbinf.info.cluster as usize;
  371. println!(" {i}: glyph_id = {glyph_id}, cluster = {cluster}");
  372. }
  373. }
  374. #[test]
  375. fn custom_emoji() {
  376. let ftlib = ft::Library::init().unwrap();
  377. let font_data = include_bytes!("../../darkirc-emoji-svg.ttf") as &[u8];
  378. let face = ftlib.new_memory_face2(font_data, 0).unwrap();
  379. let mut faces = vec![face];
  380. let text = "\u{f0001}";
  381. let glyphs = shape(&mut faces, text);
  382. //print_glyphs("", &glyphs);
  383. }
  384. }