pub struct RhythmLineMetrics { /* private fields */ }Expand description
Vertical metrics of one shaped line on the rhythm grid.
Unlike FontRhythm, which carries a resolved style
(with its font size and optional cap/x heights), this is the minimal value
a renderer needs to place one already-shaped line: the line’s reported
ascent/descent, its height in whole rhythm units, and the grid. In
gpui, feed it WrappedLine::ascent() / descent() — the shaped maxima
over the line’s explicit font runs — and every visual line of that
WrappedLine lands on the grid, because wrapped lines advance by the same
whole-row line height.
The renderer chooses line_rhythms; min_line_rhythms
suggests the smallest count whose line box contains that metric envelope, and
overflows_line_box reports when the chosen
count is smaller. Keeping a smaller count is valid — the baseline stays on
the grid and the reported envelope overflows symmetrically via negative
half-leading, exactly as CSS line boxes behave. This does not claim that
every glyph’s typographic or raster ink stays inside the line box.
covering picks the count the other way round: over a
known set of faces, before anything is shaped.
A shaped empty line has zero ascent and descent; place empty lines with
the style’s FontRhythm metrics instead so blank
lines keep the style’s baseline position.
§Examples
use rhythm_gpui::{Rhythm, RhythmLineMetrics};
let grid = Rhythm::new(8.0);
// A shaped line whose tallest run gives ascent 15.2, descent 4.1.
let line = RhythmLineMetrics::new(15.2, 4.1, 3, grid);
// Land its baseline on the 5th grid line below the block top: the paint
// origin is where the line box's top edge goes.
let origin_y = line.paint_origin_for(grid.height(5));
assert!((origin_y + line.baseline_above() - grid.height(5)).abs() < 1e-4);Implementations§
Source§impl RhythmLineMetrics
impl RhythmLineMetrics
Sourcepub fn new(ascent: f32, descent: f32, line_rhythms: u32, grid: Rhythm) -> Self
pub fn new(ascent: f32, descent: f32, line_rhythms: u32, grid: Rhythm) -> Self
Build from a shaped line’s metrics: ascent and descent in logical
pixels (both non-negative, e.g. gpui’s WrappedLine::ascent() /
descent()), and the line height in whole rhythm units.
§Panics
Panics when ascent or descent is negative or non-finite, or when
line_rhythms is zero.
Sourcepub fn at_least(
ascent: f32,
descent: f32,
line_rhythms: u32,
grid: Rhythm,
) -> Self
pub fn at_least( ascent: f32, descent: f32, line_rhythms: u32, grid: Rhythm, ) -> Self
Like new, but grows the line box to
min_line_rhythms when line_rhythms is too
small to contain the reported ascent/descent envelope. Use it when the
configured line height is a floor rather than a fixed virtualization
budget.
§Panics
Panics under the same conditions as new, or when the
minimum fitting count does not fit in u32.
Sourcepub fn covering(metrics: &[RhythmLineMetrics], grid: Rhythm) -> Self
pub fn covering(metrics: &[RhythmLineMetrics], grid: Rhythm) -> Self
The smallest line box on grid containing every line in metrics:
the maximum ascent and the maximum descent over the set, in the
largest of their line heights, grown to
min_line_rhythms when that combined metric
envelope no longer fits.
A line shapes to the maxima over its explicit font runs, so no line drawn from a caller-supplied set of face metrics can exceed the box covering that set. Folding a style’s whole known set — its own face and the faces its runs explicitly use (bold, inline code, or an explicit CJK or emoji face) — at catalog-build time makes the line’s metric envelope a property of construction rather than one each shaped line has to be checked for. Glyph-level fallback faces selected later by a platform shaper are outside this set unless the caller supplies their metrics. Nothing here shapes text: the count is known at startup, so a block’s height follows from its line count alone, which is what a virtualized renderer needs.
Take the count, not the box, into placement: this value’s
ascent/descent describe a hypothetical line reaching both maxima
at once, so keep building each line’s metrics from its own shaped
values — at this line_rhythms — and every
baseline still lands on the grid.
§Examples
use rhythm_gpui::{Rhythm, RhythmLineMetrics};
let grid = Rhythm::new(8.0);
// A body style, and a display face its lines can mix in.
let body = RhythmLineMetrics::new(14.67, 3.51, 3, grid);
let display = RhythmLineMetrics::new(28.8, 6.4, 3, grid);
// One static row budget for the style: three rows cannot hold the
// display face's ascent/descent envelope, so the covering box is five.
let budget = RhythmLineMetrics::covering(&[body, display], grid);
assert_eq!(budget.line_rhythms(), 5);
// Every mixture of the two fits it, including the worst case.
let worst = RhythmLineMetrics::new(28.8, 6.4, budget.line_rhythms(), grid);
assert!(!worst.overflows_line_box());§Panics
Panics when metrics is empty, when an entry was built on a
different grid, or when the minimum fitting count does not fit in
u32.
Sourcepub const fn descent(&self) -> f32
pub const fn descent(&self) -> f32
The reported shaped descent below the baseline, non-negative.
Sourcepub const fn line_rhythms(&self) -> u32
pub const fn line_rhythms(&self) -> u32
Line height in whole rhythm units.
Sourcepub fn line_height(&self) -> f32
pub fn line_height(&self) -> f32
The line height in logical pixels: line_rhythms × grid size.
Sourcepub fn half_leading(&self) -> f32
pub fn half_leading(&self) -> f32
Extra space split above and below the ascent + descent box; negative
when that metric envelope is taller than the line box.
Sourcepub fn baseline_above(&self) -> f32
pub fn baseline_above(&self) -> f32
Distance from the line box’s top edge down to the baseline, as gpui
paints it: half_leading + ascent.
Sourcepub fn baseline_below(&self) -> f32
pub fn baseline_below(&self) -> f32
Distance from the baseline down to the line box’s bottom edge.
Sourcepub fn paint_origin_for(&self, target_baseline: f32) -> f32
pub fn paint_origin_for(&self, target_baseline: f32) -> f32
Where to place the line box’s top edge — the origin.y passed to
gpui’s WrappedLine::paint — so the baseline lands exactly on
target_baseline (both in the same coordinate space):
target_baseline − baseline_above.
Sourcepub fn min_line_rhythms(&self) -> u32
pub fn min_line_rhythms(&self) -> u32
The smallest line_rhythms whose line box contains the reported
ascent + descent envelope, at least 1. Applies the same snapping rule
as Rhythm::snap_up — at f64 precision, since shaped metrics are
summed rather than measured — so an envelope within a few rounding
steps of a whole-row height does not claim an extra row.
Advisory: the renderer decides whether to grow the line or keep its chosen height and accept the overflow.
§Panics
Panics when the minimum fitting count does not fit in u32.
Sourcepub fn overflows_line_box(&self) -> bool
pub fn overflows_line_box(&self) -> bool
Whether the reported ascent + descent envelope is taller than the
chosen line box — equivalently, whether
half_leading is negative beyond
Rhythm::snap_up’s tolerance.
Source§impl RhythmLineMetrics
Pixels-typed mirrors of the two line values that stay inside a paint
path’s Pixels chain: both reach WrappedLine::paint.
impl RhythmLineMetrics
Pixels-typed mirrors of the two line values that stay inside a paint
path’s Pixels chain: both reach WrappedLine::paint.
Only four values across this type and RhythmBlockMetrics are mirrored.
The rest of the f32 surface is read once and converted once, so it is not
mirrored: px(line.ascent()) at the call site is one conversion, while a
mirror per accessor doubles the surface to save it. Row counts are never
mirrored because they identify grid rows rather than pixel lengths.
Sourcepub fn line_height_px(&self) -> Pixels
Available on crate feature gpui only.
pub fn line_height_px(&self) -> Pixels
gpui only.line_height in Pixels — the value
WrappedLine::paint takes.
Sourcepub fn paint_origin_for_px(&self, target_baseline: Pixels) -> Pixels
Available on crate feature gpui only.
pub fn paint_origin_for_px(&self, target_baseline: Pixels) -> Pixels
gpui only.paint_origin_for in Pixels — the
origin.y for WrappedLine::paint, from a Pixels target baseline.
Trait Implementations§
Source§impl Clone for RhythmLineMetrics
impl Clone for RhythmLineMetrics
Source§fn clone(&self) -> RhythmLineMetrics
fn clone(&self) -> RhythmLineMetrics
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for RhythmLineMetrics
Source§impl Debug for RhythmLineMetrics
impl Debug for RhythmLineMetrics
Source§impl PartialEq for RhythmLineMetrics
impl PartialEq for RhythmLineMetrics
impl StructuralPartialEq for RhythmLineMetrics
Auto Trait Implementations§
impl Freeze for RhythmLineMetrics
impl RefUnwindSafe for RhythmLineMetrics
impl Send for RhythmLineMetrics
impl Sync for RhythmLineMetrics
impl Unpin for RhythmLineMetrics
impl UnsafeUnpin for RhythmLineMetrics
impl UnwindSafe for RhythmLineMetrics
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&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
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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