pagelayout

    Paginated document layout engine: format-neutral page-model IR with SVG/PDF backends.

    layout
    pagination
    docx
    svg
    pdf
    typesetting
    Download zip
    Version
    0.2.1
    License
    Apache-2.0
    Last updated
    2 days ago
    Downloads
    41

    #pagelayout

    Paginated document layout engine. Frontends (DOCX first) produce engine input; the engine measures, line-breaks, and paginates into a format-neutral page-model IR — pages of positioned glyph runs, rectangles, images, and link regions; backends (SVG first, then PDF via pdflite) transcribe the IR. Design record: docs/page-layout-engine.md at the repository root.

    Coordinates are points, y-down, origin at the page's top-left; text is positioned by baseline, and glyph runs carry their own advances so backends never re-measure.

    ///|
    test "build a one-page model" {
    let model = @pagelayout.PageModel::new()
    let font = model.add_font({ family: "Carlito", bold: false, italic: false, })
    let page = @pagelayout.Page::{ width_pt: 612, height_pt: 792, items: [], }
    page.items.push(
    Text({
    font,
    size_pt: 12,
    x_pt: 72,
    baseline_pt: 82.5,
    text: "Hi",
    advances_pt: [6.5, 6.5],
    color: @pagelayout.black,
    }),
    )
    model.pages.push(page)
    inspect(model.pages.length(), content="1")
    }

    OOXML quantities stay in typed units until the layout boundary:

    ///|
    test "unit conversions" {
    inspect(@pagelayout.Twips(1440).to_pt(), content="72")
    inspect(@pagelayout.HalfPoints(24).to_pt(), content="12")
    inspect(@pagelayout.Emu(914400).to_pt(), content="72")
    inspect(@pagelayout.EighthPoints(4).to_pt(), content="0.5")
    }

    Color

    pub(all) struct Color {
    r : Int
    g : Int
    b : Int
    } derive(Eq, ToJson,
    Debug
    )

    Solid sRGB color; each channel is 0..=255 (checked by PageModel::validate, clamped on entry by Color::rgb). No alpha in v1: solid colors keep the SVG output inside svgdiff's deterministic subset and match common document text.

    Color::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Color::equal(Color, Color) -> Bool

    Color::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Color::not_equal(x : Color, y : Color) -> Bool

    Color::rgb

    fn Color::rgb(r : Int, g : Int, b : Int) -> Color

    Build a color, clamping each channel into 0..=255. Frontends convert untrusted document values through this so every encoding of the model (Eq, JSON, hex) agrees.

    Color::to_hex

    fn Color::to_hex(self : Color) -> String

    Lowercase #rrggbb, the form both the SVG emitter and tests use. Channels are formatted modulo the valid range (see Color::rgb).

    Color::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Color::to_json(Color) -> Json

    Color::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Color::to_repr(Color) ->
    Repr

    EighthPoints

    pub(all) struct EighthPoints(Int) derive(Eq, ToJson,
    Debug
    )

    Eighths of a point — OOXML's unit for border widths (w:sz on borders).

    EighthPoints::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn EighthPoints::equal(EighthPoints, EighthPoints) -> Bool

    EighthPoints::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn EighthPoints::not_equal(x : EighthPoints, y : EighthPoints) -> Bool

    EighthPoints::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn EighthPoints::to_json(EighthPoints) -> Json

    EighthPoints::to_pt

    fn EighthPoints::to_pt(self : EighthPoints) -> Double

    Convert to points (8 eighth-points per point).

    EighthPoints::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn EighthPoints::to_repr(EighthPoints) ->
    Repr

    Emu

    pub(all) struct Emu(Int) derive(Eq, ToJson,
    Debug
    )

    English Metric Units — OOXML's unit for drawing/image extents (914400 per inch).

    Emu::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Emu::equal(Emu, Emu) -> Bool

    Emu::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Emu::not_equal(x : Emu, y : Emu) -> Bool

    Emu::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Emu::to_json(Emu) -> Json

    Emu::to_pt

    fn Emu::to_pt(self : Emu) -> Double

    Convert to points (12700 EMU per point).

    Emu::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Emu::to_repr(Emu) ->
    Repr

    FontSpec

    pub(all) struct FontSpec {
    family : String
    bold : Bool
    italic : Bool
    } derive(Eq, ToJson,
    Debug
    )

    A font face a glyph run references, by index into PageModel::fonts. family is the resolved (post font-mapping) family name; bold and italic select the face within it.

    FontSpec::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn FontSpec::equal(FontSpec, FontSpec) -> Bool

    FontSpec::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn FontSpec::not_equal(x : FontSpec, y : FontSpec) -> Bool

    FontSpec::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn FontSpec::to_json(FontSpec) -> Json

    FontSpec::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn FontSpec::to_repr(FontSpec) ->
    Repr

    GlyphRun

    pub(all) struct GlyphRun {
    font : Int
    size_pt : Double
    x_pt : Double
    baseline_pt : Double
    text : String
    advances_pt : Array[Double]
    color : Color
    } derive(Eq, ToJson,
    Debug
    )

    A run of text on one baseline in one font/size/color. advances_pt[i] is the horizontal advance of the char at index i of text (UTF-16 code units; the trailing surrogate of a pair carries advance 0).

    GlyphRun::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn GlyphRun::equal(GlyphRun, GlyphRun) -> Bool

    GlyphRun::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn GlyphRun::not_equal(x : GlyphRun, y : GlyphRun) -> Bool

    GlyphRun::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn GlyphRun::to_json(GlyphRun) -> Json

    GlyphRun::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn GlyphRun::to_repr(GlyphRun) ->
    Repr

    GlyphRun::width_pt

    fn GlyphRun::width_pt(self : GlyphRun) -> Double

    Total advance of the run: where the next run on the same baseline starts.

    HalfPoints

    pub(all) struct HalfPoints(Int) derive(Eq, ToJson,
    Debug
    )

    Half-points — OOXML's unit for font sizes (w:sz).

    HalfPoints::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn HalfPoints::equal(HalfPoints, HalfPoints) -> Bool

    HalfPoints::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn HalfPoints::not_equal(x : HalfPoints, y : HalfPoints) -> Bool

    HalfPoints::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn HalfPoints::to_json(HalfPoints) -> Json

    HalfPoints::to_pt

    fn HalfPoints::to_pt(self : HalfPoints) -> Double

    Convert to points (2 half-points per point).

    HalfPoints::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn HalfPoints::to_repr(HalfPoints) ->
    Repr

    ImageItem

    pub(all) struct ImageItem {
    x_pt : Double
    y_pt : Double
    w_pt : Double
    h_pt : Double
    data : Bytes
    mime : String
    } derive(Eq, ToJson,
    Debug
    )

    A placed raster image; data is the encoded file, not pixels.

    ImageItem::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn ImageItem::equal(ImageItem, ImageItem) -> Bool

    ImageItem::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn ImageItem::not_equal(x : ImageItem, y : ImageItem) -> Bool

    ImageItem::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn ImageItem::to_json(ImageItem) -> Json

    ImageItem::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn ImageItem::to_repr(ImageItem) ->
    Repr

    LinkRegion

    pub(all) struct LinkRegion {
    x_pt : Double
    y_pt : Double
    w_pt : Double
    h_pt : Double
    target : String
    } derive(Eq, ToJson,
    Debug
    )

    An interactive region (hyperlink); geometry only, painted by nothing.

    LinkRegion::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn LinkRegion::equal(LinkRegion, LinkRegion) -> Bool

    LinkRegion::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn LinkRegion::not_equal(x : LinkRegion, y : LinkRegion) -> Bool

    LinkRegion::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn LinkRegion::to_json(LinkRegion) -> Json

    LinkRegion::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn LinkRegion::to_repr(LinkRegion) ->
    Repr

    Page

    pub(all) struct Page {
    width_pt : Double
    height_pt : Double
    items : Array[PageItem]
    } derive(Eq, ToJson,
    Debug
    )

    A single laid-out page: physical size plus its positioned items.

    Page::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Page::equal(Page, Page) -> Bool

    Page::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Page::not_equal(x : Page, y : Page) -> Bool

    Page::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Page::to_json(Page) -> Json

    Page::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Page::to_repr(Page) ->
    Repr

    PageItem

    pub(all) enum PageItem {
    Text(GlyphRun)
    Rect(RectItem)
    Image(ImageItem)
    Link(LinkRegion)
    } derive(Eq, ToJson,
    Debug
    )

    One positioned item on a page, in painter's order.

    PageItem::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn PageItem::equal(PageItem, PageItem) -> Bool

    PageItem::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn PageItem::not_equal(x : PageItem, y : PageItem) -> Bool

    PageItem::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn PageItem::to_json(PageItem) -> Json

    PageItem::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn PageItem::to_repr(PageItem) ->
    Repr

    PageModel

    pub(all) struct PageModel {
    fonts : Array[FontSpec]
    pages : Array[Page]
    } derive(Eq, ToJson,
    Debug
    )

    The layout engine's complete output: interned fonts plus pages.

    PageModel::add_font

    fn PageModel::add_font(self : PageModel, spec : FontSpec) -> Int

    Intern spec, returning its index for GlyphRun::font.

    PageModel::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn PageModel::equal(PageModel, PageModel) -> Bool

    PageModel::new

    fn PageModel::new() -> PageModel

    An empty model to accumulate fonts and pages into.

    PageModel::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn PageModel::not_equal(x : PageModel, y : PageModel) -> Bool

    PageModel::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn PageModel::to_json(PageModel) -> Json

    PageModel::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn PageModel::to_repr(PageModel) ->
    Repr

    PageModel::validate

    fn PageModel::validate(self : PageModel) -> Array[String]

    Check every structural invariant; return one human-readable message per violation (empty means the model is well-formed):

    • every GlyphRun has exactly one advance per UTF-16 code unit of its text, a non-negative size, and a font index into fonts;
    • every RectItem has non-negative extents, and its stroke and stroke_w_pt agree (both present or both absent);
    • every color channel is within 0..=255;
    • every page has positive extents.

    RectItem

    pub(all) struct RectItem {
    x_pt : Double
    y_pt : Double
    w_pt : Double
    h_pt : Double
    fill : Color?
    stroke : Color?
    stroke_w_pt : Double
    } derive(Eq, ToJson,
    Debug
    )

    Axis-aligned filled and/or stroked rectangle. Doubles as underlines, table borders, and shading (thin or filled).

    RectItem::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn RectItem::equal(RectItem, RectItem) -> Bool

    RectItem::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn RectItem::not_equal(x : RectItem, y : RectItem) -> Bool

    RectItem::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn RectItem::to_json(RectItem) -> Json

    RectItem::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn RectItem::to_repr(RectItem) ->
    Repr

    Twips

    pub(all) struct Twips(Int) derive(Eq, ToJson,
    Debug
    )

    Twentieths of a point — OOXML's unit for indents, spacing, margins, page sizes (w:twip).

    Twips::equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Twips::equal(Twips, Twips) -> Bool

    Twips::not_equal

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Twips::not_equal(x : Twips, y : Twips) -> Bool

    Twips::to_json

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Twips::to_json(Twips) -> Json

    Twips::to_pt

    fn Twips::to_pt(self : Twips) -> Double

    Convert to points (20 twips per point).

    Twips::to_repr

    #deprecated("implicit trait-method promotion is being removed; call via the trait")
    fn Twips::to_repr(Twips) ->
    Repr

    black

    let black : Color

    Default document text color.