Align glyphs in a LayoutRun to baseline
This commit is contained in:
parent
3640b5e1ef
commit
c2bef6a345
3 changed files with 37 additions and 11 deletions
|
|
@ -119,9 +119,9 @@ pub struct LayoutRun<'a> {
|
||||||
pub rtl: bool,
|
pub rtl: bool,
|
||||||
/// The array of layout glyphs to draw
|
/// The array of layout glyphs to draw
|
||||||
pub glyphs: &'a [LayoutGlyph],
|
pub glyphs: &'a [LayoutGlyph],
|
||||||
/// Y offset of line
|
/// Y offset to baseline of line
|
||||||
pub line_y: f32,
|
pub line_y: f32,
|
||||||
/// width of line
|
/// Width of line
|
||||||
pub line_w: f32,
|
pub line_w: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,7 +187,6 @@ pub struct LayoutRunIter<'b> {
|
||||||
line_i: usize,
|
line_i: usize,
|
||||||
layout_i: usize,
|
layout_i: usize,
|
||||||
remaining_len: usize,
|
remaining_len: usize,
|
||||||
line_y: f32,
|
|
||||||
total_layout: i32,
|
total_layout: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,7 +221,6 @@ impl<'b> LayoutRunIter<'b> {
|
||||||
line_i: 0,
|
line_i: 0,
|
||||||
layout_i: 0,
|
layout_i: 0,
|
||||||
remaining_len: bottom_cropped_layout_lines,
|
remaining_len: bottom_cropped_layout_lines,
|
||||||
line_y: buffer.metrics.y_offset(),
|
|
||||||
total_layout: 0,
|
total_layout: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -248,11 +246,15 @@ impl<'b> Iterator for LayoutRunIter<'b> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.line_y += self.buffer.metrics.line_height;
|
let line_y = self.line_i as f32 * self.buffer.metrics.line_height;
|
||||||
if self.line_y - self.buffer.metrics.y_offset() > self.buffer.height {
|
|
||||||
|
if line_y > self.buffer.height {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let glyph_height = layout_line.max_ascent + layout_line.max_descent;
|
||||||
|
let centering_offset = (self.buffer.metrics.line_height - glyph_height) / 2.0;
|
||||||
|
|
||||||
return self.remaining_len.checked_sub(1).map(|num| {
|
return self.remaining_len.checked_sub(1).map(|num| {
|
||||||
self.remaining_len = num;
|
self.remaining_len = num;
|
||||||
LayoutRun {
|
LayoutRun {
|
||||||
|
|
@ -260,7 +262,7 @@ impl<'b> Iterator for LayoutRunIter<'b> {
|
||||||
text: line.text(),
|
text: line.text(),
|
||||||
rtl: shape.rtl,
|
rtl: shape.rtl,
|
||||||
glyphs: &layout_line.glyphs,
|
glyphs: &layout_line.glyphs,
|
||||||
line_y: self.line_y,
|
line_y: line_y + centering_offset + layout_line.max_ascent,
|
||||||
line_w: layout_line.w,
|
line_w: layout_line.w,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -298,10 +300,6 @@ impl Metrics {
|
||||||
line_height: self.line_height * scale,
|
line_height: self.line_height * scale,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn y_offset(&self) -> f32 {
|
|
||||||
self.font_size - self.line_height
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Metrics {
|
impl fmt::Display for Metrics {
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,10 @@ pub struct LayoutGlyph {
|
||||||
pub struct LayoutLine {
|
pub struct LayoutLine {
|
||||||
/// Width of the line
|
/// Width of the line
|
||||||
pub w: f32,
|
pub w: f32,
|
||||||
|
/// Maximum ascent of the glyphs in line
|
||||||
|
pub max_ascent: f32,
|
||||||
|
/// Maximum descent of the glyphs in line
|
||||||
|
pub max_descent: f32,
|
||||||
/// Glyphs in line
|
/// Glyphs in line
|
||||||
pub glyphs: Vec<LayoutGlyph>,
|
pub glyphs: Vec<LayoutGlyph>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
src/shape.rs
24
src/shape.rs
|
|
@ -62,6 +62,7 @@ fn shape_fallback(
|
||||||
let run = &line[start_run..end_run];
|
let run = &line[start_run..end_run];
|
||||||
|
|
||||||
let font_scale = font.rustybuzz().units_per_em() as f32;
|
let font_scale = font.rustybuzz().units_per_em() as f32;
|
||||||
|
let metrics = font.as_swash().metrics(&[]);
|
||||||
|
|
||||||
let mut buffer = rustybuzz::UnicodeBuffer::new();
|
let mut buffer = rustybuzz::UnicodeBuffer::new();
|
||||||
buffer.set_direction(if span_rtl {
|
buffer.set_direction(if span_rtl {
|
||||||
|
|
@ -101,6 +102,8 @@ fn shape_fallback(
|
||||||
y_advance,
|
y_advance,
|
||||||
x_offset,
|
x_offset,
|
||||||
y_offset,
|
y_offset,
|
||||||
|
ascent: metrics.ascent / f32::from(metrics.units_per_em),
|
||||||
|
descent: metrics.descent / f32::from(metrics.units_per_em),
|
||||||
font_id: font.id(),
|
font_id: font.id(),
|
||||||
glyph_id: info.glyph_id.try_into().expect("failed to cast glyph ID"),
|
glyph_id: info.glyph_id.try_into().expect("failed to cast glyph ID"),
|
||||||
//TODO: color should not be related to shaping
|
//TODO: color should not be related to shaping
|
||||||
|
|
@ -272,6 +275,7 @@ fn shape_skip(
|
||||||
let font = font.as_swash();
|
let font = font.as_swash();
|
||||||
|
|
||||||
let charmap = font.charmap();
|
let charmap = font.charmap();
|
||||||
|
let metrics = font.metrics(&[]);
|
||||||
let glyph_metrics = font.glyph_metrics(&[]).scale(1.0);
|
let glyph_metrics = font.glyph_metrics(&[]).scale(1.0);
|
||||||
|
|
||||||
line[start_run..end_run]
|
line[start_run..end_run]
|
||||||
|
|
@ -288,6 +292,8 @@ fn shape_skip(
|
||||||
y_advance: 0.0,
|
y_advance: 0.0,
|
||||||
x_offset: 0.0,
|
x_offset: 0.0,
|
||||||
y_offset: 0.0,
|
y_offset: 0.0,
|
||||||
|
ascent: metrics.ascent / f32::from(metrics.units_per_em),
|
||||||
|
descent: metrics.descent / f32::from(metrics.units_per_em),
|
||||||
font_id,
|
font_id,
|
||||||
glyph_id,
|
glyph_id,
|
||||||
color_opt: attrs.color_opt,
|
color_opt: attrs.color_opt,
|
||||||
|
|
@ -305,6 +311,8 @@ pub struct ShapeGlyph {
|
||||||
pub y_advance: f32,
|
pub y_advance: f32,
|
||||||
pub x_offset: f32,
|
pub x_offset: f32,
|
||||||
pub y_offset: f32,
|
pub y_offset: f32,
|
||||||
|
pub ascent: f32,
|
||||||
|
pub descent: f32,
|
||||||
pub font_id: fontdb::ID,
|
pub font_id: fontdb::ID,
|
||||||
pub glyph_id: u16,
|
pub glyph_id: u16,
|
||||||
pub color_opt: Option<Color>,
|
pub color_opt: Option<Color>,
|
||||||
|
|
@ -749,6 +757,8 @@ impl ShapeLine {
|
||||||
let start_x = if self.rtl { line_width } else { 0.0 };
|
let start_x = if self.rtl { line_width } else { 0.0 };
|
||||||
let mut x;
|
let mut x;
|
||||||
let mut y;
|
let mut y;
|
||||||
|
let mut max_ascent: f32 = 0.;
|
||||||
|
let mut max_descent: f32 = 0.;
|
||||||
|
|
||||||
// This would keep the maximum number of spans that would fit on a visual line
|
// This would keep the maximum number of spans that would fit on a visual line
|
||||||
// If one span is too large, this variable will hold the range of words inside that span
|
// If one span is too large, this variable will hold the range of words inside that span
|
||||||
|
|
@ -987,6 +997,8 @@ impl ShapeLine {
|
||||||
let mut glyphs = Vec::with_capacity(1);
|
let mut glyphs = Vec::with_capacity(1);
|
||||||
x = start_x;
|
x = start_x;
|
||||||
y = 0.;
|
y = 0.;
|
||||||
|
max_ascent = 0.;
|
||||||
|
max_descent = 0.;
|
||||||
let alignment_correction = match (align, self.rtl) {
|
let alignment_correction = match (align, self.rtl) {
|
||||||
(Align::Left, true) => line_width - visual_line.w,
|
(Align::Left, true) => line_width - visual_line.w,
|
||||||
(Align::Left, false) => 0.,
|
(Align::Left, false) => 0.,
|
||||||
|
|
@ -1037,6 +1049,8 @@ impl ShapeLine {
|
||||||
.push(glyph.layout(font_size, x, y, x_advance, span.level));
|
.push(glyph.layout(font_size, x, y, x_advance, span.level));
|
||||||
}
|
}
|
||||||
y += y_advance;
|
y += y_advance;
|
||||||
|
max_ascent = max_ascent.max(glyph.ascent);
|
||||||
|
max_descent = max_descent.max(glyph.descent);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i in *starting_word..*ending_word + 1 {
|
for i in *starting_word..*ending_word + 1 {
|
||||||
|
|
@ -1070,6 +1084,8 @@ impl ShapeLine {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
y += y_advance;
|
y += y_advance;
|
||||||
|
max_ascent = max_ascent.max(glyph.ascent);
|
||||||
|
max_descent = max_descent.max(glyph.descent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1112,6 +1128,8 @@ impl ShapeLine {
|
||||||
}
|
}
|
||||||
x += x_advance;
|
x += x_advance;
|
||||||
y += y_advance;
|
y += y_advance;
|
||||||
|
max_ascent = max_ascent.max(glyph.ascent);
|
||||||
|
max_descent = max_descent.max(glyph.descent);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i in *starting_word..*ending_word + 1 {
|
for i in *starting_word..*ending_word + 1 {
|
||||||
|
|
@ -1145,6 +1163,8 @@ impl ShapeLine {
|
||||||
}
|
}
|
||||||
x += x_advance;
|
x += x_advance;
|
||||||
y += y_advance;
|
y += y_advance;
|
||||||
|
max_ascent = max_ascent.max(glyph.ascent);
|
||||||
|
max_descent = max_descent.max(glyph.descent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1156,6 +1176,8 @@ impl ShapeLine {
|
||||||
mem::swap(&mut glyphs, &mut glyphs_swap);
|
mem::swap(&mut glyphs, &mut glyphs_swap);
|
||||||
layout_lines.push(LayoutLine {
|
layout_lines.push(LayoutLine {
|
||||||
w: if self.rtl { start_x - x } else { x },
|
w: if self.rtl { start_x - x } else { x },
|
||||||
|
max_ascent: max_ascent * font_size,
|
||||||
|
max_descent: max_descent * font_size,
|
||||||
glyphs: glyphs_swap,
|
glyphs: glyphs_swap,
|
||||||
});
|
});
|
||||||
push_line = false;
|
push_line = false;
|
||||||
|
|
@ -1164,6 +1186,8 @@ impl ShapeLine {
|
||||||
if push_line {
|
if push_line {
|
||||||
layout_lines.push(LayoutLine {
|
layout_lines.push(LayoutLine {
|
||||||
w: 0.0,
|
w: 0.0,
|
||||||
|
max_ascent: max_ascent * font_size,
|
||||||
|
max_descent: max_descent * font_size,
|
||||||
glyphs: Default::default(),
|
glyphs: Default::default(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue