Skip to main content

text/
rendering.rs

1// Per-face raster policy. Layout advances, document fonts and legacy renderers
2// keep their original contracts; styles opt in only for their own UI faces.
3use crate::Text;
4
5/// Glyph rasterization independent of font metrics and text editing coordinates.
6#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
7#[non_exhaustive]
8pub enum FontRaster {
9    /// Original x-height fitting and downward quarter-pixel positioning.
10    #[default]
11    Legacy,
12    /// Preserve the outline scale and round to the nearest quarter pixel.
13    Natural,
14}
15
16impl FontRaster {
17    pub(crate) fn position(self, pen: i32) -> i32 {
18        match self {
19            Self::Legacy => pen,
20            Self::Natural => ((pen as i64 + if pen < 0 { 31 } else { 32 }) >> 6)
21                .saturating_mul(64).clamp(i32::MIN as i64, i32::MAX as i64) as i32,
22        }
23    }
24}
25
26impl Text {
27    /// Raster policy of a registered face. Unknown ids follow the fallback face.
28    pub fn font_raster(&self, font: u32) -> FontRaster {
29        self.slot_idx(font).map_or(FontRaster::Legacy, |i| self.slots[i].raster)
30    }
31
32    /// Change only this face's rasterization; invalidate cached masks on change.
33    /// Returns false for an unregistered id. Measuring and caret advances are unchanged.
34    pub fn set_font_raster(&mut self, font: u32, raster: FontRaster) -> bool {
35        let Some(i) = self.slot_idx(font).filter(|i| *i == font as usize) else { return false; };
36        if self.slots[i].raster != raster {
37            self.slots[i].raster = raster;
38            self.gc_flush();
39        }
40        true
41    }
42}