emblema_text/lib.rs
1//! Packing rasterized glyph coverage into a texture, and placing the result.
2//!
3//! This crate takes coverage bitmaps and answers where each one sits. It does
4//! not produce them: turning an outline into coverage needs a font parser, and
5//! that is out of scope here -- bring `swash` or `ttf-parser` and hand the
6//! coverage over. Shaping and layout are out of scope for the same reason;
7//! bring `cosmic-text` or `parley`. The boundary is what lets the atlas be
8//! tested with no font anywhere in the tree, against bitmaps whose contents
9//! are known exactly.
10//!
11//! Named here because this header claimed them and they would each change what
12//! a caller has to do: subpixel positioning, signed-distance-field coverage
13//! above a threshold size, and color glyphs drawn as image quads are **not
14//! implemented**. Nor is paging -- a full atlas is repacked and then doubled,
15//! which [`atlas`] explains and which was chosen over pages because a page
16//! boundary splits a glyph run into more than one draw.
17
18pub mod atlas;
19
20pub use atlas::{Atlas, AtlasError, AtlasRect, Coverage, GlyphKey};
21
22/// One glyph, placed.
23///
24/// The position is the glyph's top-left corner in user space, and the size is
25/// what it covers there. Both come from the caller: shaping decides where
26/// glyphs go and this does not shape. Keeping the destination separate from the
27/// atlas rectangle is what lets a glyph be drawn at a size other than the one
28/// it was rasterized at, which a caller doing so knowingly may want.
29#[derive(Debug, Clone, Copy, PartialEq)]
30pub struct PositionedGlyph {
31 pub key: GlyphKey,
32 pub position: [f32; 2],
33 pub size: [f32; 2],
34}
35
36impl PositionedGlyph {
37 /// A glyph drawn at the size its coverage was rasterized at.
38 pub fn new(key: GlyphKey, position: [f32; 2], rect: AtlasRect) -> Self {
39 Self {
40 key,
41 position,
42 size: [rect.width as f32, rect.height as f32],
43 }
44 }
45}