use super::*;
use crate::vector::CompileCache;
pub(crate) type SharedLayouts = Arc<Mutex<BTreeMap<ParagraphSpec, Arc<ParagraphLayout>>>>;
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct SpanSpec {
pub(super) text: Arc<str>,
pub(super) family: Option<Arc<str>>,
pub(super) size: Option<u64>,
pub(super) weight: Option<u16>,
pub(super) italic: bool,
}
impl From<&TextSpan> for SpanSpec {
fn from(span: &TextSpan) -> Self {
Self {
text: span.text.clone(),
family: span.family.clone(),
size: span.size.map(f64::to_bits),
weight: span.weight.map(|weight| weight.0),
italic: span.italic,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct ParagraphSpec {
pub(super) spans: Vec<SpanSpec>,
pub(super) family: Arc<str>,
pub(super) size: u64,
pub(super) weight: u16,
pub(super) line_height: u64,
pub(super) spacing: u64,
pub(super) width: Option<u64>,
pub(super) alignment: TextAlignment,
}
#[derive(Clone, Debug)]
pub struct ParagraphStyle {
pub(super) cache: CompileCache<ParagraphSpec, Result<Arc<ParagraphLayout>, ValidationError>>,
pub(super) fills: Arc<[Option<Paint>]>,
pub(super) fonts: Option<FontLibrary>,
}
impl ParagraphStyle {
pub fn new(text: impl Into<Arc<str>>) -> Self {
Self::rich([TextSpan::new(text)])
}
pub fn rich(spans: impl IntoIterator<Item = TextSpan>) -> Self {
let spans = spans.into_iter().take(257).collect::<Vec<_>>();
Self {
fills: spans.iter().map(|span| span.fill.clone()).collect(),
cache: CompileCache::new(ParagraphSpec {
spans: spans.iter().map(SpanSpec::from).collect(),
family: "".into(),
size: 24.0f64.to_bits(),
weight: FontWeight::NORMAL.0,
line_height: 1.3f64.to_bits(),
spacing: 0.0f64.to_bits(),
width: None,
alignment: TextAlignment::Start,
}),
fonts: None,
}
}
pub(super) fn spec(&self) -> &ParagraphSpec {
self.cache.key()
}
pub(super) fn with_spans(&self, spans: Vec<SpanSpec>, fills: Vec<Option<Paint>>) -> Self {
Self {
cache: self.cache.map_key(|spec| spec.spans = spans),
fills: fills.into(),
fonts: self.fonts.clone(),
}
}
fn rekey(mut self, change: impl FnOnce(&mut ParagraphSpec)) -> Self {
self.cache = self.cache.map_key(change);
self
}
pub fn family(self, family: impl Into<Arc<str>>) -> Self {
let family = family.into();
self.rekey(|spec| spec.family = family)
}
pub fn size(self, size: f64) -> Self {
self.rekey(|spec| spec.size = size.to_bits())
}
pub fn weight(self, weight: FontWeight) -> Self {
self.rekey(|spec| spec.weight = weight.0)
}
pub fn line_height(self, height: f64) -> Self {
self.rekey(|spec| spec.line_height = height.to_bits())
}
pub fn letter_spacing(self, spacing: f64) -> Self {
self.rekey(|spec| spec.spacing = spacing.to_bits())
}
pub fn max_width(self, width: f64) -> Self {
self.rekey(|spec| spec.width = Some(width.to_bits()))
}
pub fn alignment(self, alignment: TextAlignment) -> Self {
self.rekey(|spec| spec.alignment = alignment)
}
pub fn fonts(mut self, fonts: &FontLibrary) -> Self {
self.fonts = Some(fonts.clone());
self
}
}