core: graphics: adjust size for glyphs outside regular vertical bounds
Some glyphs, specifically some Arabic text, may have a top that is higher than the ascent value of the font, or a bottom that is lower than the descent value of the font. For glyphs that fit inside the area, the ascent and descent should be used for aligning with the top or bottom of a key respectively. For glyphs that do not, align the top and bottom of the text with the top and bottom of the key.
This commit is contained in:
parent
8ae15780b7
commit
70775b8350
1 changed files with 52 additions and 20 deletions
|
|
@ -16,6 +16,7 @@ use rgb::alt::BGRA;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::cmp;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::atomic::AtomicPtr;
|
use std::sync::atomic::AtomicPtr;
|
||||||
|
|
@ -73,12 +74,17 @@ pub trait Display {
|
||||||
fn end(&mut self, x: u32, y: u32, width: u32, height: u32);
|
fn end(&mut self, x: u32, y: u32, width: u32, height: u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TextRaster {
|
||||||
|
img: ImgVec<u8>,
|
||||||
|
y: usize,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Graphics<D: Display> {
|
pub struct Graphics<D: Display> {
|
||||||
disp: D,
|
disp: D,
|
||||||
fonts: Vec<(String, freetype::FT_Long)>,
|
fonts: Vec<(String, freetype::FT_Long)>,
|
||||||
fontbufs: Vec<Vec<u8>>,
|
fontbufs: Vec<Vec<u8>>,
|
||||||
labels: HashMap<String, ImgVec<u8>>,
|
labels: HashMap<String, TextRaster>,
|
||||||
sublabels: HashMap<String, ImgVec<u8>>,
|
sublabels: HashMap<String, TextRaster>,
|
||||||
ft: AtomicPtr<freetype::FT_LibraryRec_>,
|
ft: AtomicPtr<freetype::FT_LibraryRec_>,
|
||||||
|
|
||||||
x_scale: f64,
|
x_scale: f64,
|
||||||
|
|
@ -279,7 +285,7 @@ impl<D: Display> Graphics<D> {
|
||||||
ftface
|
ftface
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rasterize_text(&mut self, size: f64, text: &str) -> ImgVec<u8>
|
fn rasterize_text(&mut self, size: f64, text: &str) -> TextRaster
|
||||||
{
|
{
|
||||||
let ftface = self.open_font_for_text(text).unwrap();
|
let ftface = self.open_font_for_text(text).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -303,12 +309,26 @@ impl<D: Display> Graphics<D> {
|
||||||
metrics.max_advance as usize / 64 * (text.len() - 1) + glyph_width
|
metrics.max_advance as usize / 64 * (text.len() - 1) + glyph_width
|
||||||
};
|
};
|
||||||
|
|
||||||
let height = (metrics.ascender - metrics.descender) as usize / 64;
|
let y_max = cmp::max(metrics.ascender as isize / 64,
|
||||||
|
bbox.yMax as isize
|
||||||
|
* metrics.y_ppem as isize
|
||||||
|
/ units_per_em as isize);
|
||||||
|
let y_min = cmp::min(metrics.descender as isize / 64,
|
||||||
|
bbox.yMin as isize
|
||||||
|
* metrics.y_ppem as isize
|
||||||
|
/ units_per_em as isize);
|
||||||
|
let mut y = y_max as usize - metrics.ascender as usize / 64;
|
||||||
|
let height = (y_max - y_min) as usize;
|
||||||
|
|
||||||
|
println!("{} {}, {}", (-bbox.yMin) as usize,
|
||||||
|
metrics.y_ppem as usize,
|
||||||
|
metrics.descender);
|
||||||
|
|
||||||
let vec: Vec<u8> = vec![0; stride * height];
|
let vec: Vec<u8> = vec![0; stride * height];
|
||||||
let mut img = ImgVec::new(vec, stride, height);
|
let mut img = ImgVec::new(vec, stride, height);
|
||||||
|
|
||||||
let mut pen: i64 = 0;
|
let mut pen: i64 = 0;
|
||||||
|
let mut height = (y_max as i64 - metrics.descender / 64) as usize;
|
||||||
|
|
||||||
for c in text.chars() {
|
for c in text.chars() {
|
||||||
let glyph = unsafe {
|
let glyph = unsafe {
|
||||||
|
|
@ -323,7 +343,11 @@ impl<D: Display> Graphics<D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let dest_x = pen + glyph.bitmap_left as i64;
|
let dest_x = pen + glyph.bitmap_left as i64;
|
||||||
let dest_y = metrics.ascender / 64 - glyph.bitmap_top as i64;
|
let dest_y = y_max as i64 - glyph.bitmap_top as i64;
|
||||||
|
|
||||||
|
if y > dest_y as usize {
|
||||||
|
y = dest_y as usize;
|
||||||
|
}
|
||||||
|
|
||||||
let src = bitmap_to_imgref(&glyph.bitmap);
|
let src = bitmap_to_imgref(&glyph.bitmap);
|
||||||
let dest = img.sub_image_mut(dest_x as usize,
|
let dest = img.sub_image_mut(dest_x as usize,
|
||||||
|
|
@ -347,7 +371,14 @@ impl<D: Display> Graphics<D> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let vec = img.into_buf();
|
let vec = img.into_buf();
|
||||||
ImgVec::new_stride(vec, width, height, stride)
|
println!("{}, {}x{}", vec.len(), stride, height);
|
||||||
|
let img = ImgVec::new_stride(vec, width, height, stride);
|
||||||
|
img.sub_image(0, 0, width, height - y);
|
||||||
|
|
||||||
|
TextRaster {
|
||||||
|
img,
|
||||||
|
y,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -420,31 +451,31 @@ impl<D: Display> Graphics<D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_label_part(labels: &HashMap<String, ImgVec<u8>>,
|
fn draw_label_part(labels: &HashMap<String, TextRaster>,
|
||||||
x_anchor: Anchor, y_anchor: Anchor,
|
x_anchor: Anchor, y_anchor: Anchor,
|
||||||
img: &mut ImgRefMut<BGRA<u8>>,
|
dest: &mut ImgRefMut<BGRA<u8>>,
|
||||||
label: &str, fg_color: BGR<f32>)
|
label: &str, fg_color: BGR<f32>)
|
||||||
{
|
{
|
||||||
let src = labels.get(label)
|
let src = labels.get(label)
|
||||||
.expect("Layout and size should be set before drawing");
|
.expect("Layout and size should be set before drawing");
|
||||||
|
|
||||||
|
let width = src.img.width();
|
||||||
|
let height = src.img.height() - src.y;
|
||||||
|
|
||||||
let x = match x_anchor {
|
let x = match x_anchor {
|
||||||
Anchor::Min => 0,
|
Anchor::Min => 0,
|
||||||
Anchor::Center => (img.width() - src.width()) / 2,
|
Anchor::Center => (dest.width() - width) / 2,
|
||||||
Anchor::Max => img.width() - src.width(),
|
Anchor::Max => dest.width() - width,
|
||||||
};
|
};
|
||||||
|
|
||||||
let y = match y_anchor {
|
let y = match y_anchor {
|
||||||
Anchor::Min => 0,
|
Anchor::Min => 0,
|
||||||
Anchor::Center => (img.height() - src.height()) / 2,
|
Anchor::Center => (dest.height() - height) / 2,
|
||||||
Anchor::Max => img.height() - src.height(),
|
Anchor::Max => dest.height() - height,
|
||||||
};
|
};
|
||||||
|
|
||||||
let width = src.width();
|
let src = src.img.sub_image(0, src.y, width, height);
|
||||||
let height = src.height();
|
let dest = dest.sub_image_mut(x, y, width, height);
|
||||||
|
|
||||||
let src = src.sub_image(0, 0, width, height);
|
|
||||||
let dest = img.sub_image_mut(x, y, width, height);
|
|
||||||
|
|
||||||
convert_gray_to_bgrx(dest, src, fg_color);
|
convert_gray_to_bgrx(dest, src, fg_color);
|
||||||
}
|
}
|
||||||
|
|
@ -461,7 +492,8 @@ impl<D: Display> Graphics<D> {
|
||||||
if modifier != 0 {
|
if modifier != 0 {
|
||||||
let modifier = modifier - 1;
|
let modifier = modifier - 1;
|
||||||
if mod_state[modifier] == ModState::Locked
|
if mod_state[modifier] == ModState::Locked
|
||||||
|| mod_state[modifier] == ModState::HeldLocked {
|
|| mod_state[modifier] == ModState::HeldLocked
|
||||||
|
|| mod_state[modifier] == ModState::HeldLockedPressed {
|
||||||
return color_locked;
|
return color_locked;
|
||||||
} else if mod_state[modifier] != ModState::Released {
|
} else if mod_state[modifier] != ModState::Released {
|
||||||
return color_pressed;
|
return color_pressed;
|
||||||
|
|
@ -487,8 +519,8 @@ impl<D: Display> Graphics<D> {
|
||||||
color_label
|
color_label
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_key(labels: &HashMap<String, ImgVec<u8>>,
|
fn draw_key(labels: &HashMap<String, TextRaster>,
|
||||||
sublabels: &HashMap<String, ImgVec<u8>>,
|
sublabels: &HashMap<String, TextRaster>,
|
||||||
x_scale: f64, y_scale: f64,
|
x_scale: f64, y_scale: f64,
|
||||||
img: &mut ImgRefMut<BGRA<u8>>,
|
img: &mut ImgRefMut<BGRA<u8>>,
|
||||||
key: &Key, mod_state: &[ModState])
|
key: &Key, mod_state: &[ModState])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue