2022-10-25 12:52:46 -06:00
|
|
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
|
|
|
|
2022-12-20 12:48:37 -07:00
|
|
|
use core::fmt::Display;
|
|
|
|
|
|
2025-08-11 21:58:59 +02:00
|
|
|
use crate::{math, CacheKey, CacheKeyFlags, Color};
|
2022-11-08 08:43:27 -07:00
|
|
|
#[cfg(not(feature = "std"))]
|
|
|
|
|
use alloc::vec::Vec;
|
|
|
|
|
|
2025-08-11 21:58:59 +02:00
|
|
|
#[cfg(not(feature = "std"))]
|
|
|
|
|
use core_maths::CoreFloat;
|
2022-10-25 12:52:46 -06:00
|
|
|
|
|
|
|
|
/// A laid out glyph
|
2023-11-30 12:59:49 -07:00
|
|
|
#[derive(Clone, Debug)]
|
2022-10-25 12:52:46 -06:00
|
|
|
pub struct LayoutGlyph {
|
|
|
|
|
/// Start index of cluster in original line
|
|
|
|
|
pub start: usize,
|
|
|
|
|
/// End index of cluster in original line
|
|
|
|
|
pub end: usize,
|
2023-06-20 06:07:24 +02:00
|
|
|
/// Font size of the glyph
|
|
|
|
|
pub font_size: f32,
|
2025-07-07 09:50:40 -05:00
|
|
|
/// Font weight of the glyph
|
|
|
|
|
pub font_weight: fontdb::Weight,
|
2024-06-06 15:21:44 -06:00
|
|
|
/// Line height of the glyph, will override buffer setting
|
|
|
|
|
pub line_height_opt: Option<f32>,
|
2023-06-20 06:07:24 +02:00
|
|
|
/// Font id of the glyph
|
|
|
|
|
pub font_id: fontdb::ID,
|
|
|
|
|
/// Font id of the glyph
|
|
|
|
|
pub glyph_id: u16,
|
2022-10-25 12:52:46 -06:00
|
|
|
/// X offset of hitbox
|
|
|
|
|
pub x: f32,
|
2023-06-20 06:07:24 +02:00
|
|
|
/// Y offset of hitbox
|
|
|
|
|
pub y: f32,
|
|
|
|
|
/// Width of hitbox
|
2022-10-25 12:52:46 -06:00
|
|
|
pub w: f32,
|
2025-01-22 16:29:02 -05:00
|
|
|
/// Unicode `BiDi` embedding level, character is left-to-right if `level` is divisible by 2
|
2022-12-16 16:49:29 -07:00
|
|
|
pub level: unicode_bidi::Level,
|
2022-12-16 19:36:43 +01:00
|
|
|
/// X offset in line
|
|
|
|
|
///
|
2023-06-20 06:07:24 +02:00
|
|
|
/// If you are dealing with physical coordinates, use [`Self::physical`] to obtain a
|
|
|
|
|
/// [`PhysicalGlyph`] for rendering.
|
2022-12-16 19:36:43 +01:00
|
|
|
///
|
|
|
|
|
/// 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.
|
2022-12-15 05:04:39 +01:00
|
|
|
pub x_offset: f32,
|
2022-12-16 19:36:43 +01:00
|
|
|
/// Y offset in line
|
|
|
|
|
///
|
2023-06-20 06:07:24 +02:00
|
|
|
/// If you are dealing with physical coordinates, use [`Self::physical`] to obtain a
|
|
|
|
|
/// [`PhysicalGlyph`] for rendering.
|
2022-12-16 19:36:43 +01:00
|
|
|
///
|
|
|
|
|
/// 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.
|
2022-12-15 05:04:39 +01:00
|
|
|
pub y_offset: f32,
|
2022-10-26 14:16:48 -06:00
|
|
|
/// Optional color override
|
|
|
|
|
pub color_opt: Option<Color>,
|
2022-12-14 09:19:03 -07:00
|
|
|
/// Metadata from `Attrs`
|
|
|
|
|
pub metadata: usize,
|
2024-01-02 11:36:53 -07:00
|
|
|
/// [`CacheKeyFlags`]
|
|
|
|
|
pub cache_key_flags: CacheKeyFlags,
|
2022-10-25 12:52:46 -06:00
|
|
|
}
|
|
|
|
|
|
2023-11-30 12:59:49 -07:00
|
|
|
#[derive(Clone, Debug)]
|
2023-06-20 06:07:24 +02:00
|
|
|
pub struct PhysicalGlyph {
|
2025-01-22 16:29:02 -05:00
|
|
|
/// Cache key, see [`CacheKey`]
|
2023-06-20 06:07:24 +02:00
|
|
|
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,
|
|
|
|
|
(
|
2025-08-11 21:58:59 +02:00
|
|
|
(self.x + x_offset).mul_add(scale, offset.0),
|
|
|
|
|
math::truncf((self.y - y_offset).mul_add(scale, offset.1)), // Hinting in Y axis
|
2023-06-20 06:07:24 +02:00
|
|
|
),
|
2025-07-07 09:50:40 -05:00
|
|
|
self.font_weight,
|
2024-01-02 11:36:53 -07:00
|
|
|
self.cache_key_flags,
|
2023-06-20 06:07:24 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
PhysicalGlyph { cache_key, x, y }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 12:52:46 -06:00
|
|
|
/// A line of laid out glyphs
|
2023-11-30 12:59:49 -07:00
|
|
|
#[derive(Clone, Debug)]
|
2022-10-25 12:52:46 -06:00
|
|
|
pub struct LayoutLine {
|
2022-12-15 04:59:31 +01:00
|
|
|
/// Width of the line
|
|
|
|
|
pub w: f32,
|
2023-06-16 01:47:35 +02:00
|
|
|
/// Maximum ascent of the glyphs in line
|
|
|
|
|
pub max_ascent: f32,
|
|
|
|
|
/// Maximum descent of the glyphs in line
|
|
|
|
|
pub max_descent: f32,
|
2024-06-07 10:52:26 -06:00
|
|
|
/// Maximum line height of any spans in line
|
|
|
|
|
pub line_height_opt: Option<f32>,
|
2022-10-25 12:52:46 -06:00
|
|
|
/// Glyphs in line
|
|
|
|
|
pub glyphs: Vec<LayoutGlyph>,
|
|
|
|
|
}
|
2022-12-20 12:48:37 -07:00
|
|
|
|
|
|
|
|
/// Wrapping mode
|
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
|
|
|
|
|
pub enum Wrap {
|
|
|
|
|
/// No wrapping
|
|
|
|
|
None,
|
|
|
|
|
/// Wraps at a glyph level
|
|
|
|
|
Glyph,
|
2024-02-01 21:51:36 -05:00
|
|
|
/// Wraps at the word level
|
2022-12-20 12:48:37 -07:00
|
|
|
Word,
|
2024-02-01 21:51:36 -05:00
|
|
|
/// Wraps at the word level, or fallback to glyph level if a word can't fit on a line by itself
|
|
|
|
|
WordOrGlyph,
|
2022-12-20 12:48:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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"),
|
2024-02-01 21:51:36 -05:00
|
|
|
Self::WordOrGlyph => write!(f, "Word Wrap or Character"),
|
2022-12-20 12:48:37 -07:00
|
|
|
Self::Glyph => write!(f, "Character"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-22 18:31:49 -07:00
|
|
|
|
|
|
|
|
/// Align or justify
|
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
|
|
|
|
|
pub enum Align {
|
|
|
|
|
Left,
|
|
|
|
|
Right,
|
|
|
|
|
Center,
|
|
|
|
|
Justified,
|
2023-07-07 21:31:17 -07:00
|
|
|
End,
|
2023-02-22 18:31:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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"),
|
2023-07-07 21:31:17 -07:00
|
|
|
Self::End => write!(f, "End"),
|
2023-02-22 18:31:49 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-23 20:43:33 +01:00
|
|
|
|
|
|
|
|
/// Metrics hinting strategy
|
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, Default)]
|
|
|
|
|
pub enum Hinting {
|
|
|
|
|
/// No metrics hinting.
|
|
|
|
|
///
|
|
|
|
|
/// Glyphs will have subpixel coordinates.
|
|
|
|
|
///
|
|
|
|
|
/// This is the default.
|
|
|
|
|
#[default]
|
|
|
|
|
Disabled,
|
|
|
|
|
|
|
|
|
|
/// Metrics hinting.
|
|
|
|
|
///
|
|
|
|
|
/// Glyphs will be snapped to integral coordinates in the X-axis during layout.
|
|
|
|
|
/// This can improve readability for smaller text and/or low-DPI screens.
|
|
|
|
|
///
|
|
|
|
|
/// However, in order to get the right effect, you must use physical coordinates
|
|
|
|
|
/// during layout and avoid further scaling when rendering. Otherwise, the rounding
|
|
|
|
|
/// errors can accumulate and glyph distances may look erratic.
|
|
|
|
|
///
|
|
|
|
|
/// In other words, metrics hinting makes layouting dependent of the target
|
|
|
|
|
/// resolution.
|
|
|
|
|
Enabled,
|
|
|
|
|
}
|