use zenith_core::{FontProvider, FontStyle};
use zenith_layout::{
RustybuzzEngine, ShapeRequest, TextDirection, TextLayoutEngine, ZenithGlyphRun,
};
use crate::ir::Color;
use super::shape::ResolvedSpan;
pub(in crate::compile) const DROPCAP_GAP_FACTOR: f64 = 0.25;
const CAP_HEIGHT_RATIO: f64 = 0.714;
pub(in crate::compile) struct DropCap {
pub(in crate::compile) run: ZenithGlyphRun,
pub(in crate::compile) advance: f64,
pub(in crate::compile) color: Color,
pub(in crate::compile) lines: usize,
}
pub(in crate::compile) struct DropCapInitial {
ch: char,
color: Color,
style: FontStyle,
}
pub(in crate::compile) fn take_drop_cap_initial(
spans: &mut [ResolvedSpan],
) -> Option<DropCapInitial> {
let donor = spans.iter_mut().find(|s| !s.text.is_empty())?;
let first = donor.text.chars().next()?;
donor.text = donor.text.chars().skip(1).collect();
Some(DropCapInitial {
ch: first,
color: donor.color,
style: donor.style,
})
}
pub(in crate::compile) fn drop_cap_font_size(body_font_size: f64, line_height: f64, n: u32) -> f32 {
(body_font_size + (n as f64 - 1.0) * line_height / CAP_HEIGHT_RATIO).max(1.0) as f32
}
pub(in crate::compile) fn shape_drop_cap(
initial: &DropCapInitial,
families: &[String],
weight: u16,
cap_size: f32,
n: u32,
engine: &RustybuzzEngine,
fonts: &dyn FontProvider,
) -> Option<DropCap> {
let glyph = initial.ch.to_string();
let req = ShapeRequest {
text: &glyph,
families,
weight,
style: initial.style,
font_size: cap_size,
direction: TextDirection::Ltr,
};
let run = engine
.shape_with_fallback(&req, fonts)
.ok()?
.runs
.into_iter()
.next()?;
let advance = run.advance_width as f64;
Some(DropCap {
run,
advance,
color: initial.color,
lines: n as usize,
})
}