Skip to main content

FontRhythm

Struct FontRhythm 

Source
pub struct FontRhythm { /* private fields */ }
Expand description

Vertical metrics of one text style participating in the rhythm grid.

ascent and descent are resolved at font_size (logical pixels, both positive). Line height is expressed in whole rhythm units, which is what keeps consecutive lines of the same style on the grid.

Implementations§

Source§

impl FontRhythm

Source

pub fn from_metrics( font_size: f32, line_rhythms: u32, ascent: f32, descent: f32, ) -> Self

Build from real font metrics resolved at font_size.

§Panics

Panics when font_size or ascent is not finite and positive, when line_rhythms is zero, or when descent is not finite and non-negative.

Source

pub fn from_platform_metrics( font_size: f32, line_rhythms: u32, ascent: f32, descent: f32, cap_height: f32, x_height: f32, ) -> Self

Build from platform-reported metrics, normalizing conventions.

Some platforms report table metrics in the OpenType sign convention where descent is negative below the baseline (gpui on macOS does), so ascent and descent are taken by magnitude. Non-finite or non-positive cap and x heights are treated as unavailable and become None.

§Panics

Panics under the same conditions as Self::from_metrics after normalization (e.g. a zero ascent).

Source

pub fn from_baseline_ratio( font_size: f32, line_rhythms: u32, baseline_ratio: f32, ) -> Self

Compatibility constructor for a Plumber/rhythm-sass baseline-ratio (0 < ratio < 1), using the em-box approximation the Sass library assumed: ascent = (1 - ratio) * font_size, descent = ratio * font_size.

Prefer Self::from_metrics: the ratio is itself derived from metrics ((em + descent - ascent) / (2 * em)) and the em-box model slightly misplaces the baseline for fonts whose ascent + descent != em.

§Panics

Panics when baseline_ratio is not strictly between 0 and 1, when font_size is not finite and positive, or when line_rhythms is zero.

Source

pub const fn font_size(&self) -> f32

Font size in logical pixels.

Source

pub const fn line_rhythms(&self) -> u32

Line height in whole rhythm units.

Source

pub const fn ascent(&self) -> f32

Distance from the baseline up to the top of the ascent box, positive.

Source

pub const fn descent(&self) -> f32

Distance from the baseline down to the bottom of the descent box, positive.

Source

pub const fn cap_height(&self) -> Option<f32>

Height of capital letters above the baseline, if known.

Source

pub const fn x_height(&self) -> Option<f32>

Height of a lowercase x above the baseline, if known.

Source

pub fn baseline_ratio(&self) -> f32

The Plumber-style baseline ratio implied by these metrics.

Source

pub fn line_height(&self, grid: Rhythm) -> f32

The line height on grid: line_rhythms whole rhythm units.

Source

pub fn half_leading(&self, grid: Rhythm) -> f32

Extra space split above and below the ascent + descent box.

Source

pub fn baseline_above(&self, grid: Rhythm) -> f32

Distance from the top of the line box down to the baseline.

Source

pub fn baseline_below(&self, grid: Rhythm) -> f32

Distance from the baseline down to the bottom of the line box.

Source

pub fn cap_trim_top(&self, grid: Rhythm) -> Option<f32>

Invisible space between the top of the line box and the cap top: the amount a leading-trim (CSS text-box-trim) would remove. Subtract it from a top spacing (or apply as negative margin) to visually butt capitals against an edge or grid line.

Source

pub fn x_trim_top(&self, grid: Rhythm) -> Option<f32>

Like Self::cap_trim_top but trimming to the x-height.

Source

pub fn baseline_top(&self, grid: Rhythm, n: i32) -> f32

Spacing from an element’s top edge up to the nth grid line above the first baseline. Equivalent to rhythm-sass baseline-top() / rhythm-bottom().

Applied as padding-top (or margin-top), it makes the first baseline land exactly n rhythm units below the grid line at the element’s padding edge.

The result is negative when n × size is smaller than baseline_above; a negative value is meaningful as a margin but not as a padding, so pick n accordingly.

Source

pub fn baseline_bottom(&self, grid: Rhythm, n: i32) -> f32

Spacing from an element’s bottom edge down to the nth grid line below the last baseline. Equivalent to rhythm-sass baseline-bottom() / rhythm-top().

The result is negative when n × size is smaller than baseline_below; a negative value is meaningful as a margin but not as a padding, so pick n accordingly.

Source

pub fn baseline_between(&self, grid: Rhythm, below: &FontRhythm, n: i32) -> f32

Spacing from a block set in this style down to a following block set in below, measured from the bottom of this line box to the top of the below font’s line box, such that the two adjacent baselines are exactly n rhythm units apart. Equivalent to rhythm-sass baseline-between().

The result is negative when n rhythm units cannot fit both fonts’ baseline distances; negative values overlap the blocks when applied.

Source

pub fn cap_top(&self, grid: Rhythm, n: i32) -> Option<f32>

Top spacing that lands the cap ink top — not the baseline — on the nth grid line: n × size − cap_trim_top. The grid-woven analog of CSS text-box-trim: trim-start with text-box-edge: cap, for openings where the eye measures ink to edge (heroes, cards, page tops).

The block’s baselines shift off the grid by cap_height mod size; close the block with Self::cap_bottom — not Self::baseline_bottom — so it still occupies a whole number of rhythm rows and everything after it stays in rhythm.

None when this style has no usable cap height. CJK faces report one anyway, so on ideographic text this anchor returns Some while trimming to the wrong ink: ideographs are not seated on the baseline, and the envelope their ink is drawn to is the ideographic character face, not a cap height. Anchor those with RhythmBlockMetrics::ink_anchored, or with RhythmIcfAnchor::span under the gpui feature. Worse, the reported value need not describe any glyph: PingFang SC publishes sCapHeight 0.860 em, a copy of its sTypoAscender, while its Latin H actually reaches 0.714 em (Hiragino Sans GB, by contrast, reports its true 0.766 em). Treat a CJK face’s cap and x heights as unverified.

§Examples
use rhythm_gpui::{FontRhythm, Rhythm};

let grid = Rhythm::new(8.0);
// Georgia-like 28px heading on a 5-unit (40px) line.
let heading = FontRhythm::from_platform_metrics(28.0, 5, 25.68, -6.14, 19.40, 13.48);

// Open: the capitals' ink starts exactly on the 3rd grid line…
let pt = heading.cap_top(grid, 3).unwrap();
assert!((pt + heading.cap_trim_top(grid).unwrap() - grid.height(3)).abs() < 1e-3);

// …and the paired closer returns the trim, so the block spans whole rows.
let pb = heading.cap_bottom(grid, 0).unwrap();
let block = pt + heading.line_height(grid) + pb;
assert!((block - 64.0).abs() < 1e-3); // 8 whole rows: what follows stays in rhythm
Source

pub fn cap_bottom(&self, grid: Rhythm, n: i32) -> Option<f32>

Bottom spacing pairing Self::cap_top: n × size + cap_trim_top, returning at the bottom exactly what cap_top trimmed at the top so the block occupies a whole number of rhythm rows — for any number of wrapped lines, since lines advance by whole rows. Equivalently, the bottom edge lands n + line_rhythms units below the last line’s cap top.

None when this style has no usable cap height.

Source

pub fn line_metrics(&self, grid: Rhythm) -> RhythmLineMetrics

This style’s line placement on grid as a RhythmLineMetrics — the same value a shaped line produces, so a custom renderer can place single-style text (and empty lines) through one code path.

Source

pub fn drop_cap( &self, grid: Rhythm, cap: &FontRhythm, lines: u32, ) -> DropCapRhythm

Solve a drop cap sunk lines lines deep into text set in self.

cap carries the cap face’s metrics resolved at any font size (metrics scale linearly, so the probe size is irrelevant); its line_rhythms is ignored. The solved font size makes the cap face’s capital span from the first line’s cap top down to the lines-th baseline, and DropCapRhythm::top anchors the baseline there. A face without a usable cap height falls back to the classic 0.7 em approximation, which can only misplace the visual top — the baseline anchor stays exact.

Drop caps are a Latin convention; CJK paragraphs conventionally open with a first-line indent instead, so there is deliberately no ideographic dual of this solver. A CJK face passed as cap is solved from its reported (Latin-glyph) cap height like any other face.

§Examples
use rhythm_gpui::{FontRhythm, Rhythm};

let grid = Rhythm::new(8.0);
// Georgia-like metrics at 16px on a 3-unit (24px) line.
let body = FontRhythm::from_platform_metrics(16.0, 3, 14.67, -3.51, 11.09, 7.70);
let cap = body.drop_cap(grid, &body, 3);

// The capital spans two body lines plus the body cap height…
let span = 2.0 * body.line_height(grid) + body.cap_height().unwrap();
assert!((cap.metrics().cap_height().unwrap() - span).abs() < 1e-3);
// …and `top` lands its baseline exactly on the third body baseline.
let target = body.baseline_above(grid) + 2.0 * body.line_height(grid);
assert!((cap.top() + cap.metrics().baseline_above(grid) - target).abs() < 1e-3);
§Panics

Panics when lines is zero or lines × line_rhythms overflows u32.

Trait Implementations§

Source§

impl Clone for FontRhythm

Source§

fn clone(&self) -> FontRhythm

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for FontRhythm

Source§

impl Debug for FontRhythm

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for FontRhythm

Source§

fn eq(&self, other: &FontRhythm) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for FontRhythm

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more