refactor(text): clarify line adjustment inputs

This commit is contained in:
Dylan M. Taylor
2026-10-27 17:47:12 +00:00
parent efad21adb5
commit dec8b90e3a
17 changed files with 52 additions and 43 deletions
+28 -26
View File
@@ -87,6 +87,33 @@ fn fitness(r: f64, ragged: bool) -> u8 {
}
}
/// Adjustment ratio for a candidate line; `None` means a ragged line is already too long.
fn adjustment_ratio(natural: f64, width: f64, stretch: f64, shrink: f64, last: bool, p: &Params) -> Option<f64> {
if p.ragged {
if natural > width + EPS {
return None;
}
return Some(if last && !p.justify_last {
((width * SHORT_LAST - natural) / (width * SHORT_LAST_ZONE).max(1.0)).max(0.0)
} else {
(width - natural).max(0.0) / (width * RAG_ZONE).max(1.0)
});
}
Some(if natural < width {
if last && !p.justify_last {
0.0
} else if stretch > EPS {
(width - natural) / stretch
} else {
f64::INFINITY
}
} else if natural > width {
if shrink > EPS { (width - natural) / shrink } else { f64::NEG_INFINITY }
} else {
0.0
})
}
/// Compose the paragraph `g` into lines. `width(k)` is the available width of line `k`;
/// `start_credit(i)` is the width a wrapped line starting at glyph `i` gives back (Mojikumi sets
/// an opening bracket there flush with the line's start); `cands` are the break opportunities
@@ -146,32 +173,7 @@ pub(crate) fn compose(
let natural = w[t] - w[a.pos] - credit + bp.hyphen;
let lw = width(a.line);
// Adjustment ratio, badness and whether the line ends the active node's reach.
let ratio = if p.ragged {
if natural > lw + EPS {
// Ragged lines never shrink; longer lines from this node only get worse.
continue;
}
if last && !p.justify_last {
((lw * SHORT_LAST - natural) / (lw * SHORT_LAST_ZONE).max(1.0)).max(0.0)
} else {
(lw - natural).max(0.0) / (lw * RAG_ZONE).max(1.0)
}
} else {
let (stretch, shrink) = (st[t] - st[a.pos], sh[t] - sh[a.pos]);
if natural < lw {
if last && !p.justify_last {
0.0
} else if stretch > EPS {
(lw - natural) / stretch
} else {
f64::INFINITY
}
} else if natural > lw {
if shrink > EPS { (lw - natural) / shrink } else { f64::NEG_INFINITY }
} else {
0.0
}
};
let Some(ratio) = adjustment_ratio(natural, lw, st[t] - st[a.pos], sh[t] - sh[a.pos], last, p) else { continue };
if ratio < -1.0 {
// Too long already; longer lines from this node only get worse.
continue;
+1 -1
View File
@@ -1,7 +1,7 @@
use super::face::{FontBytes, FontFace, Variation};
use super::names::{name, norm};
use super::traits::FaceStyle;
use super::*;
use super::{HashMap, Location, MetadataProvider, NEXT_ID, Ordering, Size, StringId, Tag};
/// `face` at the axis settings `variations` (user units), as face `id`: its names, kind, italic
/// and file, and its weight the `wght` setting when there is one.
+1 -1
View File
@@ -1,5 +1,5 @@
use super::traits::FontTraits;
use super::*;
use super::{Arc, ColourContent, GlyphImage, HashMap, IMAGE_CACHE_BYTES, IMAGE_CACHE_MAX, PathBuf};
/// One installed family found by the system font scan: its name and the file of each style.
#[derive(Debug, Default)]
+3 -1
View File
@@ -17,7 +17,9 @@ use super::scan::{file_face_names, is_font_file};
use super::traits::faces_published;
#[cfg(not(target_arch = "wasm32"))]
use super::traits::{Alias, FaceStyle};
use super::*;
use super::{Arc, AtomicU64, FontDb, FontPaths, HashMap, Mutex, Ordering, Path, PathBuf, RwLock, StringId};
#[cfg(not(target_arch = "wasm32"))]
use super::{ScanStamp, modified};
impl FontDb {
/// A database holding the bundled fonts, whose system font scan reads `font_dirs` (folders,
+1 -1
View File
@@ -1,4 +1,4 @@
use super::*;
use super::{Path, PathBuf};
/// A font file holding `tables` (tag, data), sorted by tag as table directories are.
#[cfg(any(test, not(target_arch = "wasm32")))]
+1 -1
View File
@@ -1,7 +1,7 @@
use super::build::base_values;
use super::names::{localized, name};
use super::traits::{FaceKeys, FontTraits};
use super::*;
use super::{Arc, GlyphId, HashMap, Location, LocationRef, MetadataProvider, Size, StringId};
/// The family used when a requested family is unknown (Illustrator's Myriad Pro analogue).
pub const FALLBACK_FAMILY: &str = "Source Sans 3";
+1 -1
View File
@@ -1,5 +1,5 @@
use super::face::FontFace;
use super::*;
use super::{BezPath, OutlinePen};
/// Is glyph `gid` of `face` (as `font`) drawn from an SVG document, if it has one: the face has
/// SVG glyphs, and the glyph no COLR layers, which come first.
+6 -1
View File
@@ -1,3 +1,5 @@
#[cfg(not(target_arch = "wasm32"))]
use super::PathBuf;
use super::build::{instanced, style_distance, style_italic, style_weight};
use super::cache::Catalog;
use super::face::{FALLBACK_FAMILY, FontFace, MAX_LIVE_INSTANCES, Variation, VariationAxis};
@@ -8,7 +10,10 @@ use super::names::{norm, norm_chars, script_families};
#[cfg(not(target_arch = "wasm32"))]
use super::scan::{enumerate_faces, font_files};
use super::traits::{Alias, FontMatch, FontTraits};
use super::*;
use super::{
Arc, BezPath, CANONICAL_CACHE_MAX, Color, ColourContent, DrawSettings, FontDb, GlyphId, GlyphImage, MetadataProvider, NEXT_ID, OUTLINE_CACHE_MAX,
Ordering, Size,
};
impl FontDb {
/// The family's own name and the style for a name given in a document: any of a family's
+1 -1
View File
@@ -1,4 +1,4 @@
use super::*;
use super::{MetadataProvider, StringId};
#[cfg(not(target_arch = "wasm32"))]
#[derive(Default)]
+1 -1
View File
@@ -4,7 +4,7 @@ use super::dirs::sfnt_of;
use super::face::{MAX_AXES, MAX_INSTANCES};
use super::names::{all_names, name, norm};
use super::traits::{FaceKeys, FaceStyle, FontTraits, face_styles};
use super::*;
use super::{FileRef, MetadataProvider, Path, StringId, Tag};
/// The named instances of a variable font face (its `fvar` table) as styles of the face's family,
/// named by their subfamily names, without the default instance (the face itself) and without
+1 -1
View File
@@ -1,7 +1,7 @@
use super::face::{MAX_AXES, Variation};
use super::names::{MAX_LEGACY_NAMES, all_names, localized, name, native_family_name, norm};
use super::scan::named_instances;
use super::*;
use super::{MetadataProvider, StringId};
/// The names a face answers to besides its (English) family and style, normalized ([`norm`]):
/// its family in every language (typographic, else legacy: `ヒラギノ角ゴシック`), its style likewise
+2 -2
View File
@@ -1,8 +1,8 @@
//! Curved projected rings shared by a cap and its adjoining body faces.
use vectorcraft_geom::{CubicBez, Shape};
use vectorcraft_geom::{CubicBez, ParamCurve, Shape};
use super::*;
use super::{BezPath, Face, PathData, Point, Rect, Revolve, V3, Vec2, eye_distance, perspective_scale, project_face};
const CURVE_TOLERANCE: f64 = 0.001;
const MAX_RING_CURVES: usize = 32_768;
+1 -1
View File
@@ -1,5 +1,5 @@
use super::rings::{MAX_PIECES, MAX_PLANE_POINTS, MAX_SOLID_POINTS, inset, left, rings, signed_area};
use super::*;
use super::{Bevel, Extrude, Facet, FillRule, MAX_FACES, PathData, Point, Rect, Revolve, V3, View, eye_distance, perspective_scale};
/// Turns 3D points into document points and shades faces for one view.
pub(super) struct Camera {
+1 -1
View File
@@ -1,7 +1,7 @@
use super::build::{Builder, Camera, Order, Turn, check_bounds, cuts, fit, newell, outward};
use super::membrane::{Edges, MAX_MATERIAL_SEGMENTS, Membrane, cell_triangles, clip, filled, material};
use super::rings::{MAX_SOLID_POINTS, rings, signed_area};
use super::*;
use super::{Facet, FillRule, Inflate, MAX_FACES, PathData, Point, Rect, V3, Vec2, View};
/// A shape to inflate: its rings and the membrane under them on the grid of the bounds.
struct Puff {
+1 -1
View File
@@ -1,6 +1,6 @@
use super::build::segment_distance;
use super::rings::{MAX_PLANE_POINTS, contains, left, rings, signed_area};
use super::*;
use super::{FillRule, PathData, Point, Rect, Vec2};
/// The edges of `rings` filed in a grid of square buckets, so the nearest edge to a point is
/// found among the buckets around it rather than among all the edges.
+1 -1
View File
@@ -1,4 +1,4 @@
use super::*;
use super::{FillRule, ParamCurve, PathData, Point, Rect};
/// Outline points Extrude & Bevel and Inflate sample at most: every point costs walls, bevel
/// bands and distance tests.
+1 -1
View File
@@ -82,7 +82,7 @@ fn main() -> ExitCode {
/// Workspace root (parent of the xtask crate).
pub fn root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).parent().expect("xtask has a parent dir").to_path_buf()
Path::new(env!("CARGO_MANIFEST_DIR")).join("..")
}
/// Tracked and untracked (not ignored) files that exist, relative to `root`.