font.rs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. use config::Config;
  2. use freetype as ft;
  3. use fontconfig_sys::*;
  4. use ui::ext;
  5. use ui::ext::ConnectionExt;
  6. use ui::util;
  7. use ui::x11;
  8. use xcb;
  9. use std::cell::RefCell;
  10. use std::collections::HashMap;
  11. use std::ffi::{CString, CStr};
  12. use std::mem;
  13. use std::ptr;
  14. use std::sync::{Once, ONCE_INIT};
  15. static FC_INIT: Once = ONCE_INIT;
  16. struct Font {
  17. pub id: xcb::render::Glyphset,
  18. face: ft::Face<'static>,
  19. char_widths: RefCell<HashMap<char, u16>>
  20. }
  21. impl Font {
  22. pub fn new(conn: &xcb::Connection, face: ft::Face<'static>) -> Font {
  23. let format = conn.get_pict_format(ext::PictFormat::ARGB32);
  24. let id = conn.generate_id();
  25. xcb::render::create_glyph_set(conn, id, format);
  26. Font {
  27. id: id,
  28. face: face,
  29. char_widths: RefCell::new(HashMap::new())
  30. }
  31. }
  32. pub fn load_glyph(&self, conn: &xcb::Connection, charcode: char) -> Option<u16> {
  33. if self.char_widths.borrow().contains_key(&charcode) {
  34. return self.char_widths.borrow().get(&charcode).map(|r| *r)
  35. }
  36. if self.face.get_char_index(charcode as usize) == 0 {
  37. return None
  38. }
  39. match self.face.load_char(charcode as usize, ft::face::RENDER | ft::face::TARGET_LCD) {
  40. Ok(_) => {
  41. let glyph = self.face.glyph();
  42. let bitmap = glyph.bitmap();
  43. let pixel_width = (bitmap.width() / 3) as usize;
  44. let pixel_height = bitmap.rows() as usize;
  45. let info = xcb::render::Glyphinfo::new(
  46. pixel_width as u16,
  47. pixel_height as u16,
  48. -glyph.bitmap_left() as i16,
  49. glyph.bitmap_top() as i16,
  50. (glyph.advance().x / 64) as i16,
  51. (glyph.advance().y / 64) as i16
  52. );
  53. let stride = bitmap.width() as usize + (pixel_width & 3); // round up to 4 somehow
  54. let source = bitmap.buffer();
  55. let pixels = pixel_height * pixel_width;
  56. let mut buf = Vec::with_capacity(pixels * 4);
  57. for i in 0..pixel_height {
  58. let offset = i * stride;
  59. for j in 0..pixel_width {
  60. let offset = offset + j * 3;
  61. buf.push(source[offset+2]);
  62. buf.push(source[offset+1]);
  63. buf.push(source[offset]);
  64. buf.push(0);
  65. }
  66. }
  67. let width = (glyph.advance().x / 64) as u16;
  68. xcb::render::add_glyphs(conn, self.id, &[charcode as u32], &[info], buf.as_slice());
  69. self.char_widths.borrow_mut().insert(charcode, width);
  70. Some(width)
  71. },
  72. _ => None
  73. }
  74. }
  75. pub fn baseline_offset(&self, height: u16) -> i16 {
  76. self.face.load_char('X' as usize, ft::face::LoadFlag::empty()).unwrap();
  77. let ascender = self.face.glyph().metrics().horiBearingY / 64;
  78. (height as i16 - ascender as i16) / 2
  79. }
  80. }
  81. pub struct TextGroup<'a> {
  82. pub text: &'a str,
  83. pub glyphset: xcb::render::Glyphset
  84. }
  85. pub struct RenderableText<'a> {
  86. pub width: u16,
  87. groups: Vec<TextGroup<'a>>
  88. }
  89. impl<'a> RenderableText<'a> {
  90. pub fn render(&self, conn: &xcb::Connection, pen: xcb::render::Picture, pic: xcb::render::Picture, x: u16, y: u16) {
  91. let mut cmds = util::GlyphCmd::new();
  92. let mut default_glyphset = 0;
  93. cmds.set_position(x, y);
  94. for group in self.groups.iter() {
  95. default_glyphset = group.glyphset;
  96. cmds.set_glyphset(group.glyphset);
  97. cmds.add_text(group.text);
  98. }
  99. xcb::render::composite_glyphs_32(
  100. conn,
  101. xcb::render::PICT_OP_OVER as u8,
  102. pen,
  103. pic,
  104. 0,
  105. default_glyphset,
  106. 0, 0,
  107. cmds.as_ref()
  108. );
  109. }
  110. }
  111. pub struct FontLoader {
  112. conn: x11::Connection,
  113. library: ft::Library,
  114. fonts: Vec<Font>
  115. }
  116. impl FontLoader {
  117. pub fn new(conn: x11::Connection) -> Self {
  118. FC_INIT.call_once(|| unsafe {
  119. assert_eq!(FcInit(), 1);
  120. });
  121. let library = ft::Library::init().unwrap();
  122. unsafe {
  123. ft::ffi::FT_Library_SetLcdFilter(library.raw(), ft::ffi::FT_LCD_FILTER_DEFAULT);
  124. };
  125. FontLoader {
  126. conn: conn,
  127. library: library,
  128. fonts: vec![]
  129. }
  130. }
  131. pub fn from_config(conn: x11::Connection, cfg: &Config) -> Self {
  132. let val = cfg.lookup("bar.fonts").unwrap();
  133. let fonts = val.as_slice().unwrap();
  134. let fonts = fonts.iter().flat_map(|elem| elem.as_str());
  135. let mut font_loader = Self::new(conn);
  136. for font in fonts {
  137. font_loader.load(font);
  138. }
  139. font_loader
  140. }
  141. fn find_face(&self, name: &str) -> Option<ft::Face<'static>> {
  142. unsafe {
  143. let slice = CString::new(name.to_string()).unwrap();
  144. let pattern = FcNameParse(slice.as_ptr() as *const u8);
  145. FcConfigSubstitute(ptr::null_mut(), pattern, FcMatchPattern);
  146. FcDefaultSubstitute(pattern);
  147. let mut result: FcResult = mem::uninitialized();
  148. let font = FcFontMatch(ptr::null_mut(), pattern, &mut result);
  149. if !font.is_null() {
  150. let field = CString::new("file").unwrap();
  151. let mut ret: *mut FcChar8 = mem::uninitialized();
  152. if FcPatternGetString(font, field.as_ptr(), 0, &mut ret) == FcResultMatch {
  153. let file = CStr::from_ptr(ret as *const i8);
  154. let path = file.to_string_lossy().to_string();
  155. let face = self.library.new_face(&path, 0).unwrap();
  156. let field = CString::new("dpi").unwrap();
  157. let mut dpi = 0.0;
  158. if FcPatternGetDouble(font, field.as_ptr(), 0, &mut dpi) != FcResultMatch {
  159. dpi = 75.0;
  160. }
  161. let field = CString::new("pixelsize").unwrap();
  162. let mut pixel_size = 0.0;
  163. if FcPatternGetDouble(font, field.as_ptr(), 0, &mut pixel_size) == FcResultMatch {
  164. face.set_pixel_sizes((96.0 / dpi * pixel_size) as u32, 0).unwrap();
  165. }
  166. return Some(face)
  167. }
  168. }
  169. None
  170. }
  171. }
  172. pub fn load(&mut self, name: &str) {
  173. if let Some(face) = self.find_face(name) {
  174. let font = Font::new(&self.conn, face);
  175. self.fonts.push(font);
  176. }
  177. else {
  178. panic!("Could not load font {}", name);
  179. }
  180. }
  181. pub fn default_offset(&self, height: u16) -> i16 {
  182. self.fonts[0].baseline_offset(height)
  183. }
  184. fn glyphset_and_width_for_char(&self, charcode: char) -> Option<(xcb::render::Glyphset, u16)> {
  185. for font in self.fonts.iter() {
  186. if let Some(width) = font.load_glyph(&self.conn, charcode) {
  187. return Some((font.id, width))
  188. }
  189. }
  190. None
  191. }
  192. pub fn create_renderable_text<'a>(&self, string: &'a str) -> RenderableText<'a> {
  193. let mut ret = vec![];
  194. let mut prev = 0;
  195. let mut id = 0;
  196. let mut width = 0;
  197. for (i, charcode) in string.char_indices() {
  198. if let Some((this_id, char_width)) = self.glyphset_and_width_for_char(charcode) {
  199. width += char_width;
  200. if i == 0 {
  201. id = this_id;
  202. }
  203. else if id != this_id {
  204. ret.push(TextGroup {
  205. text: &string[prev..i],
  206. glyphset: id
  207. });
  208. id = this_id;
  209. prev = i;
  210. }
  211. }
  212. }
  213. ret.push(TextGroup {
  214. text: &string[prev..string.len()],
  215. glyphset: id
  216. });
  217. RenderableText {
  218. width: width,
  219. groups: ret
  220. }
  221. }
  222. }