use super::glyph::*;
use crate::font_introspector::shape::cluster::OwnedGlyphCluster;
use crate::font_introspector::shape::Shaper;
use crate::font_introspector::Metrics;
use crate::layout::content::{FragmentStyleDecoration, WordCache};
use crate::layout::FragmentStyle;
use crate::sugarloaf::primitives::SugarCursor;
use crate::{Graphic, GraphicId};
#[derive(Clone, Debug, Default)]
pub struct RenderData {
pub runs: Vec<RunData>,
pub glyphs: Vec<GlyphData>,
pub detailed_glyphs: Vec<Glyph>,
pub graphics: std::collections::HashSet<GraphicId>,
}
impl RenderData {
#[inline]
pub fn is_empty(&self) -> bool {
self.runs.is_empty()
}
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn reserve(&mut self, capacity: usize) {
self.runs.reserve(capacity);
self.glyphs.reserve(capacity);
self.detailed_glyphs.reserve(capacity);
self.graphics.reserve(capacity);
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
runs: Vec::with_capacity(capacity),
glyphs: Vec::with_capacity(capacity),
detailed_glyphs: Vec::with_capacity(capacity),
graphics: std::collections::HashSet::with_capacity(capacity),
}
}
#[inline]
pub fn clear(&mut self) {
self.runs.clear();
self.glyphs.clear();
self.detailed_glyphs.clear();
self.graphics.clear();
}
}
impl RenderData {
#[allow(clippy::too_many_arguments)]
pub(super) fn push_run(
&mut self,
style: FragmentStyle,
size: f32,
line: u32,
shaper: Shaper<'_>,
shaper_cache: &mut WordCache,
) {
let metrics = shaper.metrics();
let mut glyphs = vec![];
let mut detailed_glyphs = vec![];
let mut advance = 0.;
shaper.shape_with(|c| {
shaper_cache.add_glyph_cluster(c);
let mut cluster_advance = 0.;
for glyph in c.glyphs {
cluster_advance += glyph.advance;
const MAX_SIMPLE_ADVANCE: u32 = 0x7FFF;
if glyph.x == 0. && glyph.y == 0. {
let packed_advance = (glyph.advance * 64.) as u32;
if packed_advance <= MAX_SIMPLE_ADVANCE {
glyphs.push(GlyphData {
data: glyph.id as u32 | (packed_advance << 16),
size: glyph.data as usize,
});
continue;
}
}
let detail_index = detailed_glyphs.len() as u32;
detailed_glyphs.push(Glyph::new(glyph));
glyphs.push(GlyphData {
data: GLYPH_DETAILED | detail_index,
size: glyph.data as usize,
});
}
advance += cluster_advance;
});
shaper_cache.finish();
if let Some(graphic) = style.media {
self.graphics.insert(graphic.id);
}
let run_data = RunData {
span: style,
line,
size,
detailed_glyphs,
glyphs,
ascent: metrics.ascent,
descent: metrics.descent,
leading: metrics.leading,
strikeout_offset: metrics.strikeout_offset,
strikeout_size: metrics.stroke_size,
advance,
};
self.runs.push(run_data);
}
pub(super) fn push_run_without_shaper(
&mut self,
style: FragmentStyle,
size: f32,
line: u32,
glyph_clusters: &Vec<OwnedGlyphCluster>,
metrics: &Metrics,
) -> bool {
let mut advance = 0.;
let mut glyphs = vec![];
let mut detailed_glyphs = vec![];
for c in glyph_clusters {
let mut cluster_advance = 0.;
for glyph in &c.glyphs {
cluster_advance += glyph.advance;
const MAX_SIMPLE_ADVANCE: u32 = 0x7FFF;
if glyph.x == 0. && glyph.y == 0. {
let packed_advance = (glyph.advance * 64.) as u32;
if packed_advance <= MAX_SIMPLE_ADVANCE {
glyphs.push(GlyphData {
data: glyph.id as u32 | (packed_advance << 16),
size: glyph.data as usize,
});
continue;
}
}
let detail_index = detailed_glyphs.len() as u32;
detailed_glyphs.push(Glyph::new(glyph));
glyphs.push(GlyphData {
data: GLYPH_DETAILED | detail_index,
size: glyph.data as usize,
});
}
advance += cluster_advance;
}
if let Some(graphic) = style.media {
self.graphics.insert(graphic.id);
}
let run_data = RunData {
span: style,
line,
size,
detailed_glyphs,
glyphs,
ascent: metrics.ascent,
descent: metrics.descent,
leading: metrics.leading,
strikeout_offset: metrics.strikeout_offset,
strikeout_size: metrics.stroke_size,
advance,
};
self.runs.push(run_data);
true
}
}
#[derive(Copy, Clone)]
pub struct Run<'a> {
pub(super) run: &'a RunData,
}
impl Run<'_> {
#[inline]
pub fn span(&self) -> FragmentStyle {
self.run.span
}
#[inline]
pub fn media(&self) -> Option<Graphic> {
self.run.span.media
}
#[inline]
pub fn font(&self) -> &usize {
&self.run.span.font_id
}
#[inline]
pub fn font_size(&self) -> f32 {
self.run.size
}
#[inline]
pub fn color(&self) -> [f32; 4] {
self.run.span.color
}
#[inline]
pub fn char_width(&self) -> f32 {
self.run.span.width
}
#[inline]
pub fn cursor(&self) -> Option<SugarCursor> {
self.run.span.cursor
}
#[inline]
pub fn advance(&self) -> f32 {
self.run.advance
}
#[inline]
pub fn background_color(&self) -> Option<[f32; 4]> {
self.run.span.background_color
}
#[inline]
pub fn decoration(&self) -> Option<FragmentStyleDecoration> {
self.run.span.decoration
}
#[inline]
pub fn decoration_color(&self) -> Option<[f32; 4]> {
self.run.span.decoration_color
}
}