typf-core 5.0.11

Core types and traits for the Typf text rendering pipeline
Documentation

typf-core: The Engine Room

Six stages from text to pixels. No magic, just engineering.

Text enters as Unicode chaos, exits as perfect pixels. This crate is the engine room that makes text rendering work when half your characters are Arabic and the other half are emoji.

The Pipeline: Brutal Simplicity

Every text walks this path, no shortcuts:

  1. Input Parsing - Raw strings → structured data. We don't guess encoding.
  2. Unicode Processing - Bidi, scripts, segmentation. The hard stuff.
  3. Font Selection - Right font for each character, period. Fallback that actually works.
  4. Shaping - Characters → positioned glyphs. Where HarfBuzz lives.
  5. Rendering - Glyphs → pixels/vectors. SIMD or die.
  6. Export - Your format, ready to ship.

Build Your First Pipeline

use typf_core::{Pipeline, RenderParams, ShapingParams};
use std::sync::Arc;

# use typf_core::traits::*;
# use typf_core::context::PipelineContext;
# use typf_core::error::TypfError;
# struct MyShaper;
# impl Stage for MyShaper {
#     fn name(&self) -> &'static str { "test" }
#     fn process(&self, _ctx: PipelineContext) -> Result<PipelineContext, TypfError> { unimplemented!() }
# }
# impl Shaper for MyShaper {
#     fn name(&self) -> &'static str { "test" }
#     fn shape(&self, _: &str, _: Arc<dyn FontRef>, _: &ShapingParams)
#         -> typf_core::Result<typf_core::types::ShapingResult> { unimplemented!() }
# }
# struct MyRenderer;
# impl Stage for MyRenderer {
#     fn name(&self) -> &'static str { "test" }
#     fn process(&self, _ctx: PipelineContext) -> Result<PipelineContext, TypfError> { unimplemented!() }
# }
# impl Renderer for MyRenderer {
#     fn name(&self) -> &'static str { "test" }
#     fn render(&self, _: &typf_core::types::ShapingResult, _: Arc<dyn FontRef>, _: &RenderParams)
#         -> typf_core::Result<typf_core::types::RenderOutput> { unimplemented!() }
# }
# struct MyExporter;
# impl Stage for MyExporter {
#     fn name(&self) -> &'static str { "test" }
#     fn process(&self, _ctx: PipelineContext) -> Result<PipelineContext, TypfError> { unimplemented!() }
# }
# impl Exporter for MyExporter {
#     fn name(&self) -> &'static str { "test" }
#     fn export(&self, _: &typf_core::types::RenderOutput)
#         -> typf_core::Result<Vec<u8>> { unimplemented!() }
#     fn extension(&self) -> &'static str { "png" }
#     fn mime_type(&self) -> &'static str { "image/png" }
# }
# fn load_font() -> Arc<dyn FontRef> { unimplemented!() }

let pipeline = Pipeline::builder()
    .shaper(Arc::new(MyShaper))
    .renderer(Arc::new(MyRenderer))
    .exporter(Arc::new(MyExporter))
    .build()?;

let font = load_font();
let output = pipeline.process(
    "Hello, World!",
    font,
    &ShapingParams::default(),
    &RenderParams::default(),
)?;
# Ok::<(), typf_core::TypfError>(())

The Traits That Power Everything

Want to add your own backend? Implement one of these:

  • [Stage] - The foundation every pipeline component builds upon.
  • [Shaper] - Where characters become glyphs.
  • [Renderer] - Where glyphs become images.
  • [Exporter] - Where images become files.
  • [traits::FontRef] - Your window into font data.

Data flows through the types in [types] - these structures carry the results from one stage to the next.