summaryrefslogtreecommitdiff
path: root/library/src/math/stretch.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/src/math/stretch.rs')
-rw-r--r--library/src/math/stretch.rs199
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)
- })
-}