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