use std::rc::Rc;
use cranpose_ui_graphics::{
DrawTextMeasurer, DrawTextStyle, FontStyle as DrawFontStyle, Size, TextMeasurement,
estimate_text_measurement,
};
use super::{
font::{FontFamily, FontStyle, FontWeight},
line_box::LineBox,
style::{SpanStyle, TextStyle},
unit::TextUnit,
};
pub fn text_style_for_draw_style(style: &DrawTextStyle) -> TextStyle {
let mut span_style = SpanStyle {
font_size: TextUnit::Sp(style.resolved_font_size()),
font_weight: Some(FontWeight::new(style.font_weight.value())),
font_style: Some(match style.font_style {
DrawFontStyle::Normal => FontStyle::Normal,
DrawFontStyle::Italic | DrawFontStyle::Oblique => FontStyle::Italic,
}),
..SpanStyle::default()
};
if let Some(family) = &style.font_family {
span_style.font_family = Some(FontFamily::from_name(family));
}
let letter_spacing = style.resolved_letter_spacing();
if letter_spacing != 0.0 {
span_style.letter_spacing = TextUnit::Sp(letter_spacing);
}
let mut text_style = TextStyle::from_span_style(span_style);
if let Some(line_height) = style.line_height
&& line_height.is_finite()
&& line_height > 0.0
{
text_style.paragraph_style.line_height = TextUnit::Sp(line_height);
}
text_style.paragraph_style.line_height_style = style.line_height_style;
text_style
}
pub fn draw_style_line_box(style: &DrawTextStyle) -> Option<LineBox> {
super::measure::resolved_line_box(&text_style_for_draw_style(style))
}
#[derive(Clone, Copy, Debug, Default)]
pub struct AppContextTextMeasurer;
impl AppContextTextMeasurer {
pub fn shared() -> Rc<dyn DrawTextMeasurer> {
thread_local! {
static SHARED: Rc<dyn DrawTextMeasurer> = Rc::new(AppContextTextMeasurer);
}
SHARED.with(Rc::clone)
}
}
impl DrawTextMeasurer for AppContextTextMeasurer {
fn measure_text(&self, text: &str, style: &DrawTextStyle) -> TextMeasurement {
if crate::render_state::current_app_context().is_none() {
return estimate_text_measurement(text, style);
}
let text_style = text_style_for_draw_style(style);
let annotated = super::shared_plain_annotated_string(text);
let metrics = super::measure::measure_resolved_text(&annotated, &text_style);
let line_height = if metrics.line_height.is_finite() && metrics.line_height > 0.0 {
metrics.line_height
} else {
estimate_text_measurement(text, style).line_height
};
let first_baseline = super::measure::resolved_first_baseline(&text_style)
.unwrap_or_else(|| estimate_text_measurement(text, style).first_baseline);
if text.is_empty() {
return TextMeasurement::empty(line_height, first_baseline);
}
let line_count = metrics.line_count.max(1);
TextMeasurement {
size: Size::new(metrics.width.max(0.0), line_count as f32 * line_height),
line_height,
first_baseline,
line_count,
}
}
}
#[cfg(test)]
#[path = "tests/draw_scope_text_tests.rs"]
mod tests;