cosmic_text/layout.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
// SPDX-License-Identifier: MIT OR Apache-2.0
use core::fmt::Display;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use crate::{math, CacheKey, CacheKeyFlags, Color};
/// A laid out glyph
#[derive(Clone, Debug)]
pub struct LayoutGlyph {
/// Start index of cluster in original line
pub start: usize,
/// End index of cluster in original line
pub end: usize,
/// Font size of the glyph
pub font_size: f32,
/// Line height of the glyph, will override buffer setting
pub line_height_opt: Option<f32>,
/// Font id of the glyph
pub font_id: fontdb::ID,
/// Font id of the glyph
pub glyph_id: u16,
/// X offset of hitbox
pub x: f32,
/// Y offset of hitbox
pub y: f32,
/// Width of hitbox
pub w: f32,
/// Unicode BiDi embedding level, character is left-to-right if `level` is divisible by 2
pub level: unicode_bidi::Level,
/// X offset in line
///
/// If you are dealing with physical coordinates, use [`Self::physical`] to obtain a
/// [`PhysicalGlyph`] for rendering.
///
/// This offset is useful when you are dealing with logical units and you do not care or
/// cannot guarantee pixel grid alignment. For instance, when you want to use the glyphs
/// for vectorial text, apply linear transformations to the layout, etc.
pub x_offset: f32,
/// Y offset in line
///
/// If you are dealing with physical coordinates, use [`Self::physical`] to obtain a
/// [`PhysicalGlyph`] for rendering.
///
/// This offset is useful when you are dealing with logical units and you do not care or
/// cannot guarantee pixel grid alignment. For instance, when you want to use the glyphs
/// for vectorial text, apply linear transformations to the layout, etc.
pub y_offset: f32,
/// Optional color override
pub color_opt: Option<Color>,
/// Metadata from `Attrs`
pub metadata: usize,
/// [`CacheKeyFlags`]
pub cache_key_flags: CacheKeyFlags,
}
#[derive(Clone, Debug)]
pub struct PhysicalGlyph {
/// Cache key, see [CacheKey]
pub cache_key: CacheKey,
/// Integer component of X offset in line
pub x: i32,
/// Integer component of Y offset in line
pub y: i32,
}
impl LayoutGlyph {
pub fn physical(&self, offset: (f32, f32), scale: f32) -> PhysicalGlyph {
let x_offset = self.font_size * self.x_offset;
let y_offset = self.font_size * self.y_offset;
let (cache_key, x, y) = CacheKey::new(
self.font_id,
self.glyph_id,
self.font_size * scale,
(
(self.x + x_offset) * scale + offset.0,
math::truncf((self.y - y_offset) * scale + offset.1), // Hinting in Y axis
),
self.cache_key_flags,
);
PhysicalGlyph { cache_key, x, y }
}
}
/// A line of laid out glyphs
#[derive(Clone, Debug)]
pub struct LayoutLine {
/// Width of the line
pub w: f32,
/// Maximum ascent of the glyphs in line
pub max_ascent: f32,
/// Maximum descent of the glyphs in line
pub max_descent: f32,
/// Maximum line height of any spans in line
pub line_height_opt: Option<f32>,
/// Glyphs in line
pub glyphs: Vec<LayoutGlyph>,
}
/// Wrapping mode
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum Wrap {
/// No wrapping
None,
/// Wraps at a glyph level
Glyph,
/// Wraps at the word level
Word,
/// Wraps at the word level, or fallback to glyph level if a word can't fit on a line by itself
WordOrGlyph,
}
impl Display for Wrap {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::None => write!(f, "No Wrap"),
Self::Word => write!(f, "Word Wrap"),
Self::WordOrGlyph => write!(f, "Word Wrap or Character"),
Self::Glyph => write!(f, "Character"),
}
}
}
/// Align or justify
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum Align {
Left,
Right,
Center,
Justified,
End,
}
impl Display for Align {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Left => write!(f, "Left"),
Self::Right => write!(f, "Right"),
Self::Center => write!(f, "Center"),
Self::Justified => write!(f, "Justified"),
Self::End => write!(f, "End"),
}
}
}