Type: ligatures drop past -20 or +55 tracking, as Adobe's composers do
#583 kept ligatures within +-50/1000 em. Adobe's composers are described as dropping them past about -8% and +22% of the word space (John Hudson, www-style, 2012-07): about -20 and +55 for a typical 250/1000 em space. Condensed type shows a fixed ligature sooner than expanded type does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e1d560a727
commit
5a09d1aef8
File diff suppressed because one or more lines are too long
|
|
@ -3,25 +3,27 @@
|
|||
use harfrust::{Feature, Tag};
|
||||
use vectorcraft_doc::CharStyle;
|
||||
|
||||
/// Tracking (in 1/1000 em) beyond which standard ligatures are dropped automatically.
|
||||
/// Tracking (in 1/1000 em) outside which standard ligatures are dropped automatically: tighter
|
||||
/// than the first, looser than the second.
|
||||
///
|
||||
/// Letterspaced type should not ligate: an `fi` glyph keeps its letters tight while everything
|
||||
/// around it opens up, which reads as a blot. Small tracking adjustments made to fit a line
|
||||
/// (a few thousandths either way) are not letterspacing and keep the ligatures, so only
|
||||
/// `|tracking|` above this threshold suppresses them. An explicit `liga` / `clig` in the
|
||||
/// character's own features always wins.
|
||||
pub const LIGATURE_TRACKING_LIMIT: f64 = 50.0;
|
||||
/// around it opens up (or stays open while it closes up), which reads as a blot. Small tracking
|
||||
/// adjustments made to fit a line are not letterspacing and keep the ligatures. The limits are
|
||||
/// about −8% and +22% of a typical word space (250/1000 em), the thresholds Adobe's composers are
|
||||
/// described as using (John Hudson, www-style, 2012-07): condensing shows the fixed ligature
|
||||
/// sooner than expanding. An explicit `liga` / `clig` in the character's own features always wins.
|
||||
pub const LIGATURE_TRACKING_LIMITS: (f64, f64) = (-20.0, 55.0);
|
||||
|
||||
/// OpenType features applied during shaping. Kerning, `case` and ligature suppression are driven
|
||||
/// by the character style (`kerning`, `all_caps`, `tracking`); the rest are layout-wide options.
|
||||
/// Standard ligatures are dropped when `|tracking|` exceeds [`LIGATURE_TRACKING_LIMIT`], unless
|
||||
/// Standard ligatures are dropped when tracking is outside [`LIGATURE_TRACKING_LIMITS`], unless
|
||||
/// the character's features turn `liga` (or `clig`) on explicitly.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct OtFeatures {
|
||||
/// Vertical glyph alternates (`vert`), set by the writing direction.
|
||||
pub vertical: bool,
|
||||
/// Standard ligatures (`liga`, `clig`). Suppressed automatically when `|tracking|` exceeds
|
||||
/// [`LIGATURE_TRACKING_LIMIT`], unless the character turns them on explicitly.
|
||||
/// Standard ligatures (`liga`, `clig`). Suppressed automatically when tracking is outside
|
||||
/// [`LIGATURE_TRACKING_LIMITS`], unless the character turns them on explicitly.
|
||||
pub ligatures: bool,
|
||||
/// Contextual alternates (`calt`).
|
||||
pub contextual: bool,
|
||||
|
|
@ -165,7 +167,8 @@ impl OtFeatures {
|
|||
/// Does `tracking` (1/1000 em) count as letterspacing that drops standard ligatures?
|
||||
pub fn ligatures_suppressed_by(tracking: f64) -> bool {
|
||||
// A non-finite value is not a real letterspacing request; keep the default.
|
||||
tracking.is_finite() && tracking.abs() > LIGATURE_TRACKING_LIMIT
|
||||
let (tight, loose) = LIGATURE_TRACKING_LIMITS;
|
||||
tracking.is_finite() && (tracking < tight || tracking > loose)
|
||||
}
|
||||
|
||||
/// Do `features` turn standard ligatures on explicitly (`liga`, `+liga`, `clig`, `+clig`)? The last
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ pub mod test_fonts;
|
|||
pub mod thread;
|
||||
|
||||
pub use craft_fonts::{CRAFT_FONTS, CraftFont};
|
||||
pub use features::{LIGATURE_TRACKING_LIMIT, OtFeatures, explicit_ligatures, ligatures_suppressed_by};
|
||||
pub use features::{LIGATURE_TRACKING_LIMITS, OtFeatures, explicit_ligatures, ligatures_suppressed_by};
|
||||
pub use fontdb::{FALLBACK_FAMILY, FontClass, FontDb, FontFace, FontMatch, FontTraits, style_weight, system_font_dirs};
|
||||
use kurbo::{Affine, BezPath, Point, Rect, Vec2};
|
||||
pub use layout::{layout, layout_with};
|
||||
|
|
|
|||
|
|
@ -377,9 +377,11 @@ fn opentype_ligature_switches() {
|
|||
// Small tracking adjustments (fitting a line) keep the ligature.
|
||||
assert_eq!(fi(-5.0, &[]), 1, "tracking -5 keeps fi");
|
||||
assert_eq!(fi(20.0, &[]), 1, "tracking +20 keeps fi");
|
||||
assert_eq!(fi(LIGATURE_TRACKING_LIMIT, &[]), 1, "the limit itself keeps fi");
|
||||
// Real letterspacing suppresses ligatures (as letterspaced type should)...
|
||||
let (tight, loose) = LIGATURE_TRACKING_LIMITS;
|
||||
assert_eq!((fi(tight, &[]), fi(loose, &[])), (1, 1), "the limits themselves keep fi");
|
||||
// Real letterspacing suppresses ligatures (as letterspaced type should), condensing sooner...
|
||||
assert_eq!(fi(100.0, &[]), 2, "tracking 100 drops fi");
|
||||
assert_eq!(fi(-30.0, &[]), 2, "tracking -30 drops fi");
|
||||
assert_eq!(fi(-100.0, &[]), 2, "tracking -100 drops fi");
|
||||
// ...unless the character turns them on explicitly.
|
||||
assert_eq!(fi(100.0, &["liga"]), 1, "explicit liga wins over tracking");
|
||||
|
|
|
|||
Loading…
Reference in New Issue