diff options
Diffstat (limited to 'library/src/math/stretch.rs')
| -rw-r--r-- | library/src/math/stretch.rs | 199 |
1 files changed, 0 insertions, 199 deletions
diff --git a/library/src/math/stretch.rs b/library/src/math/stretch.rs deleted file mode 100644 index 910f7a81..00000000 --- a/library/src/math/stretch.rs +++ /dev/null @@ -1,199 +0,0 @@ -use ttf_parser::math::{GlyphAssembly, GlyphConstruction, GlyphPart}; -use ttf_parser::LazyArray16; - -use super::*; - -/// Maximum number of times extenders can be repeated. -const MAX_REPEATS: usize = 1024; - -impl GlyphFragment { - /// Try to stretch a glyph to a desired height. - pub fn stretch_vertical( - self, - ctx: &MathContext, - height: Abs, - short_fall: Abs, - ) -> VariantFragment { - stretch_glyph(ctx, self, height, short_fall, false) - } - - /// Try to stretch a glyph to a desired width. - pub fn stretch_horizontal( - self, - ctx: &MathContext, - width: Abs, - short_fall: Abs, - ) -> VariantFragment { - stretch_glyph(ctx, self, width, short_fall, true) - } -} - -/// Try to stretch a glyph to a desired width or height. -/// -/// The resulting frame may not have the exact desired width. -fn stretch_glyph( - ctx: &MathContext, - mut base: GlyphFragment, - target: Abs, - short_fall: Abs, - horizontal: bool, -) -> VariantFragment { - let short_target = target - short_fall; - let mut min_overlap = Abs::zero(); - let construction = ctx - .table - .variants - .and_then(|variants| { - min_overlap = variants.min_connector_overlap.scaled(ctx); - if horizontal { - variants.horizontal_constructions - } else { - variants.vertical_constructions - } - .get(base.id) - }) - .unwrap_or(GlyphConstruction { assembly: None, variants: LazyArray16::new(&[]) }); - - // If the base glyph is good enough, use it. - let advance = if horizontal { base.width } else { base.height() }; - if short_target <= advance { - return base.into_variant(); - } - - // Search for a pre-made variant with a good advance. - let mut best_id = base.id; - let mut best_advance = base.width; - for variant in construction.variants { - best_id = variant.variant_glyph; - best_advance = base.font.to_em(variant.advance_measurement).at(base.font_size); - if short_target <= best_advance { - break; - } - } - - // This is either good or the best we've got. - if short_target <= best_advance || construction.assembly.is_none() { - base.set_id(ctx, best_id); - return base.into_variant(); - } - - // Assemble from parts. - let assembly = construction.assembly.unwrap(); - assemble(ctx, base, assembly, min_overlap, target, horizontal) -} - -/// Assemble a glyph from parts. -fn assemble( - ctx: &MathContext, - base: GlyphFragment, - assembly: GlyphAssembly, - min_overlap: Abs, - target: Abs, - horizontal: bool, -) -> VariantFragment { - // Determine the number of times the extenders need to be repeated as well - // as a ratio specifying how much to spread the parts apart - // (0 = maximal overlap, 1 = minimal overlap). - let mut full; - let mut ratio; - let mut repeat = 0; - loop { - full = Abs::zero(); - ratio = 0.0; - - let mut parts = parts(assembly, repeat).peekable(); - let mut growable = Abs::zero(); - - while let Some(part) = parts.next() { - let mut advance = part.full_advance.scaled(ctx); - if let Some(next) = parts.peek() { - let max_overlap = part - .end_connector_length - .min(next.start_connector_length) - .scaled(ctx); - - advance -= max_overlap; - growable += max_overlap - min_overlap; - } - - full += advance; - } - - if full < target { - let delta = target - full; - ratio = (delta / growable).min(1.0); - full += ratio * growable; - } - - if target <= full || repeat >= MAX_REPEATS { - break; - } - - repeat += 1; - } - - let mut selected = vec![]; - let mut parts = parts(assembly, repeat).peekable(); - while let Some(part) = parts.next() { - let mut advance = part.full_advance.scaled(ctx); - if let Some(next) = parts.peek() { - let max_overlap = - part.end_connector_length.min(next.start_connector_length).scaled(ctx); - advance -= max_overlap; - advance += ratio * (max_overlap - min_overlap); - } - - let mut fragment = base.clone(); - fragment.set_id(ctx, part.glyph_id); - selected.push((fragment, advance)); - } - - let size; - let baseline; - if horizontal { - let height = base.ascent + base.descent; - size = Size::new(full, height); - baseline = base.ascent; - } else { - let axis = scaled!(ctx, axis_height); - let width = selected.iter().map(|(f, _)| f.width).max().unwrap_or_default(); - size = Size::new(width, full); - baseline = full / 2.0 + axis; - } - - let mut frame = Frame::new(size); - let mut offset = Abs::zero(); - frame.set_baseline(baseline); - frame.meta_iter(base.meta); - - for (fragment, advance) in selected { - let pos = if horizontal { - Point::new(offset, frame.baseline() - fragment.ascent) - } else { - Point::with_y(full - offset - fragment.height()) - }; - frame.push_frame(pos, fragment.into_frame()); - offset += advance; - } - - VariantFragment { - c: base.c, - id: None, - frame, - style: base.style, - font_size: base.font_size, - italics_correction: Abs::zero(), - class: base.class, - span: base.span, - limits: base.limits, - } -} - -/// Return an iterator over the assembly's parts with extenders repeated the -/// specified number of times. -fn parts(assembly: GlyphAssembly, repeat: usize) -> impl Iterator<Item = GlyphPart> + '_ { - assembly.parts.into_iter().flat_map(move |part| { - let count = if part.part_flags.extender() { repeat } else { 1 }; - std::iter::repeat(part).take(count) - }) -} |
