Skip to main content

rdocx_layout/
lib.rs

1#![doc = include_str!("../README.md")]
2#![allow(non_camel_case_types)]
3#![allow(clippy::too_many_arguments)]
4
5pub mod block;
6mod convert;
7pub mod engine;
8pub mod input;
9pub mod notes;
10pub mod paginator;
11pub mod style_resolver;
12pub mod table;
13
14pub use input::{ImageData, LayoutInput, MediaRegistry, RevisionView};
15pub use oxml_layout::{
16    Color, DocumentMetadata, FontData, FontFile, FontId, GlyphRun, LayoutError, LayoutResult,
17    PageFrame, Point, PositionedElement, Rect, Result, SourceNodeId, SourceSpan,
18};
19
20/// Word story containing a source paragraph.
21#[derive(Debug, Clone, PartialEq, Eq, Hash)]
22pub enum WordStory {
23    Document,
24    Header { relationship_id: String },
25    Footer { relationship_id: String },
26    Footnote { id: i32 },
27    Endnote { id: i32 },
28}
29
30/// Modeled path to one paragraph in a Word story.
31#[derive(Debug, Clone, PartialEq, Eq, Hash)]
32pub struct WordSourcePath {
33    pub story: WordStory,
34    pub children: Vec<usize>,
35}
36
37/// Complete layout output plus its result-local Word source map.
38#[derive(Debug)]
39pub struct WordLayoutResult {
40    pub layout: LayoutResult,
41    pub revision_view: RevisionView,
42    source_nodes: Vec<WordSourcePath>,
43}
44
45impl WordLayoutResult {
46    /// Resolve a result-local source identity.
47    pub fn source_node(&self, id: SourceNodeId) -> Option<&WordSourcePath> {
48        self.source_nodes.get(id.get() as usize - 1)
49    }
50
51    /// Discard the Word source map and return the backend-neutral layout.
52    pub fn into_layout_result(self) -> LayoutResult {
53        self.layout
54    }
55}
56
57/// Lay out a complete DOCX document, producing positioned page frames.
58pub fn layout_document(input: &LayoutInput) -> Result<LayoutResult> {
59    engine::Engine::new().layout(input)
60}
61
62/// Lay out a complete DOCX and retain exact Word paragraph provenance.
63pub fn layout_document_with_provenance(input: &LayoutInput) -> Result<WordLayoutResult> {
64    let (layout, source_nodes) = engine::Engine::new().layout_with_provenance(input)?;
65    Ok(WordLayoutResult {
66        layout,
67        revision_view: input.revision_view,
68        source_nodes,
69    })
70}
71
72/// Lay out a DOCX with a reusable normal-font engine.
73///
74/// This hidden facade hook lets `rdocx::Document` retain expensive normal-font
75/// work without exposing cache ownership as a second public abstraction.
76#[doc(hidden)]
77pub fn layout_document_with_reusable_engine(
78    engine: &mut engine::Engine,
79    input: &LayoutInput,
80) -> Result<WordLayoutResult> {
81    let (layout, source_nodes) = engine.layout_with_provenance(input)?;
82    Ok(WordLayoutResult {
83        layout,
84        revision_view: input.revision_view,
85        source_nodes,
86    })
87}
88
89/// Lay out a DOCX using only caller-supplied and document-embedded fonts.
90#[doc(hidden)]
91pub fn layout_document_with_caller_fonts_and_provenance(
92    input: &LayoutInput,
93) -> Result<WordLayoutResult> {
94    let (layout, source_nodes) =
95        engine::Engine::new_with_caller_fonts().layout_with_provenance(input)?;
96    Ok(WordLayoutResult {
97        layout,
98        revision_view: input.revision_view,
99        source_nodes,
100    })
101}
102
103/// Lay out a DOCX using bundled fonts without system font discovery.
104pub fn layout_document_deterministic(input: &LayoutInput) -> Result<LayoutResult> {
105    engine::Engine::new_deterministic()?.layout(input)
106}
107
108/// Lay out a DOCX deterministically and retain exact Word paragraph provenance.
109pub fn layout_document_deterministic_with_provenance(
110    input: &LayoutInput,
111) -> Result<WordLayoutResult> {
112    let (layout, source_nodes) =
113        engine::Engine::new_deterministic()?.layout_with_provenance(input)?;
114    Ok(WordLayoutResult {
115        layout,
116        revision_view: input.revision_view,
117        source_nodes,
118    })
119}