1
0
Fork 0
forked from wry/wry

text: add metrics and dynamic height

This commit is contained in:
Julian Orth 2022-07-30 16:16:35 +02:00
parent 2568b7b1f5
commit 8b93957f31
4 changed files with 84 additions and 28 deletions

View file

@ -85,6 +85,7 @@ extern "C" {
ink_rect: *mut PangoRectangle, ink_rect: *mut PangoRectangle,
logical_rect: *mut PangoRectangle, logical_rect: *mut PangoRectangle,
); );
fn pango_layout_get_baseline(layout: *mut PangoLayout_) -> c::c_int;
fn pango_extents_to_pixels(inclusive: *mut PangoRectangle, nearest: *mut PangoRectangle); fn pango_extents_to_pixels(inclusive: *mut PangoRectangle, nearest: *mut PangoRectangle);
} }
@ -104,6 +105,7 @@ pub enum PangoError {
} }
#[repr(C)] #[repr(C)]
#[derive(Default)]
struct PangoRectangle { struct PangoRectangle {
x: c::c_int, x: c::c_int,
y: c::c_int, y: c::c_int,
@ -111,6 +113,8 @@ struct PangoRectangle {
height: c::c_int, height: c::c_int,
} }
const PANGO_SCALE: i32 = 1024;
pub struct CairoImageSurface { pub struct CairoImageSurface {
s: *mut cairo_surface_t, s: *mut cairo_surface_t,
} }
@ -325,18 +329,29 @@ impl PangoLayout {
pub fn inc_pixel_rect(&self) -> Rect { pub fn inc_pixel_rect(&self) -> Rect {
unsafe { unsafe {
let mut rect = PangoRectangle { let mut rect = PangoRectangle::default();
x: 0,
y: 0,
width: 0,
height: 0,
};
pango_layout_get_extents(self.l, &mut rect, ptr::null_mut()); pango_layout_get_extents(self.l, &mut rect, ptr::null_mut());
pango_extents_to_pixels(&mut rect, ptr::null_mut()); pango_extents_to_pixels(&mut rect, ptr::null_mut());
Rect::new_sized(rect.x, rect.y, rect.width, rect.height).unwrap() Rect::new_sized(rect.x, rect.y, rect.width, rect.height).unwrap()
} }
} }
pub fn logical_pixel_rect(&self) -> Rect {
unsafe {
let mut rect = PangoRectangle::default();
pango_layout_get_extents(self.l, ptr::null_mut(), &mut rect);
pango_extents_to_pixels(&mut rect, ptr::null_mut());
Rect::new_sized(rect.x, rect.y, rect.width, rect.height).unwrap()
}
}
pub fn pixel_baseline(&self) -> i32 {
unsafe {
let res = pango_layout_get_baseline(self.l);
(res as i32 + PANGO_SCALE - 1) / PANGO_SCALE
}
}
pub fn show_layout(&self) { pub fn show_layout(&self) {
unsafe { unsafe {
pango_cairo_show_layout(self.c.c.c, self.l); pango_cairo_show_layout(self.c.c.c, self.l);

View file

@ -76,14 +76,21 @@ pub fn measure(
text: &str, text: &str,
markup: bool, markup: bool,
scale: Option<f64>, scale: Option<f64>,
) -> Result<Rect, TextError> { full: bool,
) -> Result<TextMeasurement, TextError> {
let data = create_data(font, 1, 1, scale)?; let data = create_data(font, 1, 1, scale)?;
if markup { if markup {
data.layout.set_markup(text); data.layout.set_markup(text);
} else { } else {
data.layout.set_text(text); data.layout.set_text(text);
} }
Ok(data.layout.inc_pixel_rect()) let mut res = TextMeasurement::default();
res.ink_rect = data.layout.inc_pixel_rect();
if full {
res.logical_rect = data.layout.logical_pixel_rect();
res.baseline = data.layout.pixel_baseline();
}
Ok(res)
} }
pub fn render( pub fn render(
@ -96,13 +103,14 @@ pub fn render(
scale: Option<f64>, scale: Option<f64>,
) -> Result<Rc<Texture>, TextError> { ) -> Result<Rc<Texture>, TextError> {
render2( render2(
ctx, 1, width, height, 1, font, text, color, true, false, scale, ctx, 1, None, width, height, 1, font, text, color, true, false, scale,
) )
} }
fn render2( fn render2(
ctx: &Rc<RenderContext>, ctx: &Rc<RenderContext>,
x: i32, x: i32,
y: Option<i32>,
width: i32, width: i32,
height: i32, height: i32,
padding: i32, padding: i32,
@ -128,8 +136,8 @@ fn render2(
data.cctx.set_operator(CAIRO_OPERATOR_SOURCE); data.cctx.set_operator(CAIRO_OPERATOR_SOURCE);
data.cctx data.cctx
.set_source_rgba(color.r as _, color.g as _, color.b as _, color.a as _); .set_source_rgba(color.r as _, color.g as _, color.b as _, color.a as _);
data.cctx let y = y.unwrap_or((height - font_height) / 2);
.move_to(x as f64, ((height - font_height) / 2) as f64); data.cctx.move_to(x as f64, y as f64);
data.layout.show_layout(); data.layout.show_layout();
data.image.flush(); data.image.flush();
let bytes = match data.image.data() { let bytes = match data.image.data() {
@ -144,19 +152,44 @@ fn render2(
pub fn render_fitting( pub fn render_fitting(
ctx: &Rc<RenderContext>, ctx: &Rc<RenderContext>,
height: i32, height: Option<i32>,
font: &str, font: &str,
text: &str, text: &str,
color: Color, color: Color,
markup: bool, markup: bool,
scale: Option<f64>, scale: Option<f64>,
) -> Result<Rc<Texture>, TextError> { ) -> Result<Rc<Texture>, TextError> {
let rect = measure(font, text, markup, scale)?; render_fitting2(ctx, height, font, text, color, markup, scale, false).map(|(a, _)| a)
render2( }
#[derive(Debug, Copy, Clone, Default)]
pub struct TextMeasurement {
pub ink_rect: Rect,
pub logical_rect: Rect,
pub baseline: i32,
}
pub fn render_fitting2(
ctx: &Rc<RenderContext>,
height: Option<i32>,
font: &str,
text: &str,
color: Color,
markup: bool,
scale: Option<f64>,
include_measurements: bool,
) -> Result<(Rc<Texture>, TextMeasurement), TextError> {
let measurement = measure(font, text, markup, scale, include_measurements)?;
let y = match height {
Some(_) => None,
_ => Some(measurement.ink_rect.y1().neg()),
};
let res = render2(
ctx, ctx,
rect.x1().neg(), measurement.ink_rect.x1().neg(),
rect.width(), y,
height, measurement.ink_rect.width(),
height.unwrap_or(measurement.ink_rect.height()),
0, 0,
font, font,
text, text,
@ -164,5 +197,6 @@ pub fn render_fitting(
false, false,
markup, markup,
scale, scale,
) );
res.map(|r| (r, measurement))
} }

View file

@ -168,7 +168,7 @@ impl OutputNode {
}; };
let title = match text::render_fitting( let title = match text::render_fitting(
&ctx, &ctx,
texture_height, Some(texture_height),
&font, &font,
&ws.name, &ws.name,
tc, tc,
@ -219,14 +219,21 @@ impl OutputNode {
break 'set_status; break 'set_status;
} }
let tc = self.state.theme.colors.bar_text.get(); let tc = self.state.theme.colors.bar_text.get();
let title = let title = match text::render_fitting(
match text::render_fitting(&ctx, texture_height, &font, &status, tc, true, scale) { &ctx,
Ok(t) => t, Some(texture_height),
Err(e) => { &font,
log::error!("Could not render status {}: {}", status, ErrorFmt(e)); &status,
break 'set_status; tc,
} true,
}; scale,
) {
Ok(t) => t,
Err(e) => {
log::error!("Could not render status {}: {}", status, ErrorFmt(e));
break 'set_status;
}
};
let mut width = title.width(); let mut width = title.width();
if let Some(scale) = scale { if let Some(scale) = scale {
width = (width as f64 / scale).round() as _; width = (width as f64 / scale).round() as _;

View file

@ -61,7 +61,7 @@ impl PlaceholderNode {
let font = format!("monospace {}", width / 10); let font = format!("monospace {}", width / 10);
match text::render_fitting( match text::render_fitting(
&ctx, &ctx,
height, Some(height),
&font, &font,
"Fullscreen", "Fullscreen",
self.toplevel.state.theme.colors.unfocused_title_text.get(), self.toplevel.state.theme.colors.unfocused_title_text.get(),