mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-14 19:26:59 -04:00
Merge pull request #1044 from vbasky/fix/927-vertical-underline
Underline vertical graphic text
This commit is contained in:
commit
8a69dc6047
2 files changed
+92
No files matched your search
@@ -0,0 +1,59 @@
|
||||
//! Horizontal vs vertical graphic text with underline (letter A, 60 px).
|
||||
use filmcraft_geom::{Affine, Vec2};
|
||||
use filmcraft_project::graphic::{new_text_layer, new_vertical_text_layer};
|
||||
use filmcraft_project::{EffectInstance, ParamValue};
|
||||
use filmcraft_render::graphic_clip::render_graphic_layers;
|
||||
use filmcraft_render::image::Image;
|
||||
use filmcraft_time::Tick;
|
||||
|
||||
fn set(e: &mut EffectInstance, k: &str, v: ParamValue) {
|
||||
e.params.get_mut(k).unwrap_or_else(|| panic!("{k}")).value = v;
|
||||
}
|
||||
|
||||
fn draw(layer: EffectInstance) -> Image {
|
||||
let mut img = Image::new(320, 200);
|
||||
render_graphic_layers(&[layer], Tick::ZERO, (320, 200), &Affine::IDENTITY, &mut img);
|
||||
img
|
||||
}
|
||||
|
||||
fn ink_box(img: &Image) -> [usize; 4] {
|
||||
let mut b: Option<[usize; 4]> = None;
|
||||
for y in 0..img.h {
|
||||
for x in 0..img.w {
|
||||
if img.get(x, y)[3] > 0.4 {
|
||||
b = Some(match b {
|
||||
Some(a) => [a[0].min(x), a[1].min(y), a[2].max(x), a[3].max(y)],
|
||||
None => [x, y, x, y],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
b.expect("ink")
|
||||
}
|
||||
|
||||
fn count(img: &Image) -> usize {
|
||||
(0..img.h).flat_map(|y| (0..img.w).map(move |x| (x, y))).filter(|&(x, y)| img.get(x, y)[3] > 0.4).count()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn underline_horizontal_vs_vertical_letter_a() {
|
||||
let pos = Vec2::new(80.0, 100.0);
|
||||
let mut h = new_text_layer("A", pos, 60.0);
|
||||
let h_plain = draw(h.clone());
|
||||
set(&mut h, "underline", ParamValue::Bool(true));
|
||||
let h_ul = draw(h);
|
||||
let mut v = new_vertical_text_layer("A", Vec2::new(200.0, 100.0), 60.0);
|
||||
let v_plain = draw(v.clone());
|
||||
set(&mut v, "underline", ParamValue::Bool(true));
|
||||
let v_ul = draw(v);
|
||||
|
||||
assert!(count(&h_ul) > count(&h_plain) + 20, "horizontal underline adds ink");
|
||||
assert!(count(&v_ul) > count(&v_plain) + 20, "vertical underline adds ink");
|
||||
|
||||
let hb = ink_box(&h_ul);
|
||||
let hp = ink_box(&h_plain);
|
||||
let vb = ink_box(&v_ul);
|
||||
let vp = ink_box(&v_plain);
|
||||
assert!(hb[3] > hp[3] + 1, "horizontal underline sits below the letter: plain {hp:?} ul {hb:?}");
|
||||
assert!(vb[2] > vp[2] + 1, "vertical underline sits to the right of the letter: plain {vp:?} ul {vb:?}");
|
||||
}
|
||||
@@ -724,6 +724,7 @@ fn layout_vertical(text: &str, sty: &Styles, para: &ParagraphStyle, col_w: f32,
|
||||
let row = (pm.ascent + pm.descent).max(style.size * 0.5) + style.tracking * style.size / 1000.0;
|
||||
let flat = ParagraphStyle { vertical: true, ..Default::default() };
|
||||
lay.vertical = true;
|
||||
let rich = sty.rich();
|
||||
let mut base = 0usize;
|
||||
let mut ncols = 0usize;
|
||||
for (c, p) in text.split('\n').enumerate() {
|
||||
@@ -761,6 +762,21 @@ fn layout_vertical(text: &str, sty: &Styles, para: &ParagraphStyle, col_w: f32,
|
||||
}
|
||||
g
|
||||
}));
|
||||
// Underline runs down the column, to the right of the cell (the "below" side of vertical-rl).
|
||||
let y_top = baseline - pl.ascent;
|
||||
if rich {
|
||||
for (_x0, x1, si) in &pl.underlines {
|
||||
let st = sty.list[*si as usize];
|
||||
let um = fonts::face(sty.prim[*si as usize].face).metrics(st.size);
|
||||
let x = *x1 + shift - st.baseline_shift + um.underline_pos;
|
||||
lay.underlines.push([x, y_top, x + um.underline_thickness, y_top + row]);
|
||||
lay.underline_runs.push(*si);
|
||||
}
|
||||
} else if style.underline && pl.content > 0.0 {
|
||||
let x = shift + pl.left_trim + pl.content + pm.underline_pos;
|
||||
lay.underlines.push([x, y_top, x + pm.underline_thickness, y_top + row]);
|
||||
lay.underline_runs.push(0);
|
||||
}
|
||||
lay.lines.push(Line {
|
||||
range: pl.range,
|
||||
baseline,
|
||||
@@ -998,6 +1014,23 @@ mod tests {
|
||||
assert_eq!(h.lines.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vertical_underline_runs_down_the_column() {
|
||||
let s = TextStyle { underline: true, ..st(60.0) };
|
||||
let h = layout("A", &s, &ParagraphStyle::default());
|
||||
let v = layout("A", &s, &ParagraphStyle { vertical: true, ..Default::default() });
|
||||
assert_eq!(h.underlines.len(), 1);
|
||||
assert_eq!(v.underlines.len(), 1, "vertical cells get an underline");
|
||||
let [hx0, hy0, hx1, hy1] = h.underlines[0];
|
||||
let [vx0, vy0, vx1, vy1] = v.underlines[0];
|
||||
assert!(hx1 - hx0 > hy1 - hy0, "horizontal underline is a wide strip");
|
||||
assert!(vy1 - vy0 > vx1 - vx0, "vertical underline is a tall strip");
|
||||
let runs = [StyleRun { range: 0..1, style: s.clone() }];
|
||||
let rich = layout_rich("A", &st(60.0), &runs, &ParagraphStyle { vertical: true, ..Default::default() });
|
||||
assert_eq!(rich.underlines.len(), 1);
|
||||
assert_eq!(rich.underline_runs, vec![1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vertical_cells_keep_combining_marks_with_their_base() {
|
||||
let style = st(32.0);
|
||||
|
||||
Reference in new issue
Block a user