diff --git a/font/src/darwin/mod.rs b/font/src/darwin/mod.rs index 877564f..a6deba3 100644 --- a/font/src/darwin/mod.rs +++ b/font/src/darwin/mod.rs @@ -462,17 +462,31 @@ impl Font { pub fn get_glyph(&self, character: char, _size: f64, use_thin_strokes: bool) -> Result { // Render custom symbols for underline and beam cursor - if character == super::UNDERLINE_CURSOR_CHAR { - let descent = -(self.ct_font.descent() as i32); - let width = self.glyph_advance('0') as i32; - return super::get_underline_cursor_glyph(descent, width); - } else if character == super::BEAM_CURSOR_CHAR { - let metrics = self.metrics(); - let height = metrics.line_height; - let ascent = height - self.ct_font.descent() + 1.; - let width = self.glyph_advance('0') as i32; - return super::get_beam_cursor_glyph(ascent as i32, height as i32, width); - }; + match character { + super::UNDERLINE_CURSOR_CHAR => { + // Get the bottom of the bounding box + let descent = -(self.ct_font.descent() as i32); + // Get the width of the cell + let width = self.glyph_advance('0') as i32; + // Return the new custom glyph + return super::get_underline_cursor_glyph(descent, width); + }, + super::BEAM_CURSOR_CHAR => { + // Get the top of the bounding box + let metrics = self.metrics(); + let height = metrics.line_height; + let mut ascent = height - self.ct_font.descent() + 1.; + if ascent.floor() == ascent { + // Fix off-by-one with an exact X.0 ascent + ascent -= 1.; + } + // Get the width of the cell + let width = self.glyph_advance('0') as i32; + // Return the new custom glyph + return super::get_beam_cursor_glyph(ascent as i32, height as i32, width); + }, + _ => (), + } let glyph_index = self.glyph_index(character) .ok_or(Error::MissingGlyph(character))?; diff --git a/font/src/ft/mod.rs b/font/src/ft/mod.rs index 7b22fb0..765e8ef 100644 --- a/font/src/ft/mod.rs +++ b/font/src/ft/mod.rs @@ -298,7 +298,8 @@ impl FreeTypeRasterizer { match glyph_key.c { super::UNDERLINE_CURSOR_CHAR => { // Get the bottom of the bounding box - let size_metrics = face.ft_face.size_metrics() + let size_metrics = face.ft_face + .size_metrics() .ok_or(Error::MissingSizeMetrics)?; let descent = (size_metrics.descender / 64) as i32; @@ -308,10 +309,11 @@ impl FreeTypeRasterizer { // Return the new custom glyph super::get_underline_cursor_glyph(descent, width) - }, + } super::BEAM_CURSOR_CHAR => { // Get the top of the bounding box - let size_metrics = face.ft_face.size_metrics() + let size_metrics = face.ft_face + .size_metrics() .ok_or(Error::MissingSizeMetrics)?; let ascent = (size_metrics.ascender / 64) as i32 - 1; @@ -325,7 +327,7 @@ impl FreeTypeRasterizer { // Return the new custom glyph super::get_beam_cursor_glyph(ascent, height, width) - }, + } _ => { // If it's not a special char, return the normal glyph Ok(RasterizedGlyph { diff --git a/font/src/lib.rs b/font/src/lib.rs index a2580fc..f9eaaac 100644 --- a/font/src/lib.rs +++ b/font/src/lib.rs @@ -43,7 +43,7 @@ extern crate foreign_types; extern crate log; use std::hash::{Hash, Hasher}; -use std::fmt; +use std::{fmt, cmp}; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; // If target isn't macos, reexport everything from ft @@ -65,6 +65,8 @@ pub const UNDERLINE_CURSOR_CHAR: char = '\u{10a3e2}'; /// Character used for the beam cursor // This is part of the private use area and should not conflict with any font pub const BEAM_CURSOR_CHAR: char = '\u{10a3e3}'; +/// Width of the beam cursor relative to the font width +pub const BEAM_CURSOR_WIDTH_PERCENTAGE: i32 = 15; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FontDesc { @@ -211,11 +213,10 @@ impl Default for RasterizedGlyph { } // Returns a custom underline cursor character -// TODO: Make sure this works with positive/0 descent -> small fonts pub fn get_underline_cursor_glyph(descent: i32, width: i32) -> Result { // Create a new rectangle, the height is half the distance between // bounding box bottom and the baseline - let height = i32::abs(descent / 2); + let height = cmp::max(i32::abs(descent / 2), 1); let buf = vec![255u8; (width * height * 3) as usize]; // Create a custom glyph with the rectangle data attached to it @@ -230,10 +231,13 @@ pub fn get_underline_cursor_glyph(descent: i32, width: i32) -> Result small fonts -pub fn get_beam_cursor_glyph(ascent: i32, height: i32, width: i32) -> Result { - // Create a new rectangle - let beam_width = (f64::from(width) / 5.) as i32; +pub fn get_beam_cursor_glyph( + ascent: i32, + height: i32, + width: i32, +) -> Result { + // Create a new rectangle that is at least one pixel wide + let beam_width = cmp::max(width * BEAM_CURSOR_WIDTH_PERCENTAGE / 100, 1); let buf = vec![255u8; (beam_width * height * 3) as usize]; // Create a custom glyph with the rectangle data attached to it