rdocx_layout/output.rs
1//! Output types for the layout engine: positioned page frames, glyph runs, etc.
2
3/// A point in 2D space (in typographic points from the top-left corner).
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub struct Point {
6 pub x: f64,
7 pub y: f64,
8}
9
10/// An axis-aligned rectangle.
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub struct Rect {
13 pub x: f64,
14 pub y: f64,
15 pub width: f64,
16 pub height: f64,
17}
18
19/// An RGBA color with components in [0.0, 1.0].
20#[derive(Debug, Clone, Copy, PartialEq)]
21pub struct Color {
22 pub r: f64,
23 pub g: f64,
24 pub b: f64,
25 pub a: f64,
26}
27
28impl Color {
29 pub const BLACK: Color = Color {
30 r: 0.0,
31 g: 0.0,
32 b: 0.0,
33 a: 1.0,
34 };
35 pub const WHITE: Color = Color {
36 r: 1.0,
37 g: 1.0,
38 b: 1.0,
39 a: 1.0,
40 };
41
42 /// Parse a hex color string like "FF0000" to Color.
43 pub fn from_hex(hex: &str) -> Self {
44 let hex = hex.trim_start_matches('#');
45 if hex.len() >= 6 {
46 let r = u8::from_str_radix(&hex[0..2], 16).unwrap_or(0) as f64 / 255.0;
47 let g = u8::from_str_radix(&hex[2..4], 16).unwrap_or(0) as f64 / 255.0;
48 let b = u8::from_str_radix(&hex[4..6], 16).unwrap_or(0) as f64 / 255.0;
49 Color { r, g, b, a: 1.0 }
50 } else {
51 Color::BLACK
52 }
53 }
54}
55
56/// Opaque font identifier assigned by FontManager.
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
58pub struct FontId(pub u32);
59
60/// Kind of field for post-pagination substitution.
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum FieldKind {
63 /// Current page number.
64 Page,
65 /// Total number of pages.
66 NumPages,
67}
68
69/// A positioned run of shaped glyphs.
70#[derive(Debug, Clone)]
71pub struct GlyphRun {
72 /// Baseline origin of the first glyph (in points).
73 pub origin: Point,
74 /// Font identifier (from FontManager).
75 pub font_id: FontId,
76 /// Font size in points.
77 pub font_size: f64,
78 /// Shaped glyph IDs.
79 pub glyph_ids: Vec<u16>,
80 /// Per-glyph advances in points.
81 pub advances: Vec<f64>,
82 /// Original text (for PDF ToUnicode mapping).
83 pub text: String,
84 /// Text color.
85 pub color: Color,
86 /// Whether the font is bold.
87 pub bold: bool,
88 /// Whether the font is italic.
89 pub italic: bool,
90 /// If this glyph run is a field placeholder, the kind of field.
91 pub field_kind: Option<FieldKind>,
92 /// If this glyph run is a footnote/endnote reference marker, its ID.
93 pub footnote_id: Option<i32>,
94}
95
96/// A positioned element on a page.
97#[derive(Debug, Clone)]
98pub enum PositionedElement {
99 /// A run of shaped text glyphs.
100 Text(GlyphRun),
101 /// A line segment (for borders, underlines, strikethrough).
102 Line {
103 start: Point,
104 end: Point,
105 width: f64,
106 color: Color,
107 /// Optional dash pattern (dash_on, dash_off) in points. None = solid line.
108 dash_pattern: Option<(f64, f64)>,
109 },
110 /// A filled rectangle (for shading, highlights).
111 FilledRect { rect: Rect, color: Color },
112 /// An inline image.
113 Image {
114 rect: Rect,
115 data: Vec<u8>,
116 content_type: String,
117 /// Embed relationship ID (used to resolve image data post-pagination).
118 embed_id: Option<String>,
119 },
120 /// A link annotation (hyperlink).
121 LinkAnnotation { rect: Rect, url: String },
122}
123
124/// A single page of laid-out content.
125#[derive(Debug, Clone)]
126pub struct PageFrame {
127 /// 1-based page number.
128 pub page_number: usize,
129 /// Page width in points.
130 pub width: f64,
131 /// Page height in points.
132 pub height: f64,
133 /// All positioned elements on this page.
134 pub elements: Vec<PositionedElement>,
135}
136
137/// Font data for embedding in PDF output.
138#[derive(Debug, Clone)]
139pub struct FontData {
140 /// Font identifier.
141 pub id: FontId,
142 /// Font family name.
143 pub family: String,
144 /// Raw TTF/OTF bytes for PDF embedding.
145 pub data: Vec<u8>,
146 /// Face index within a font collection.
147 pub face_index: u32,
148 /// Whether this is a bold variant.
149 pub bold: bool,
150 /// Whether this is an italic variant.
151 pub italic: bool,
152}
153
154/// Document metadata to pass through to PDF output.
155#[derive(Debug, Clone, Default)]
156pub struct DocumentMetadata {
157 /// Document title.
158 pub title: Option<String>,
159 /// Document author.
160 pub author: Option<String>,
161 /// Document subject.
162 pub subject: Option<String>,
163 /// Document keywords.
164 pub keywords: Option<String>,
165 /// Creator application.
166 pub creator: Option<String>,
167}
168
169/// An outline/bookmark entry for PDF generation.
170#[derive(Debug, Clone)]
171pub struct OutlineEntry {
172 /// The heading text.
173 pub title: String,
174 /// Heading level (1 for Heading1, 2 for Heading2, etc.).
175 pub level: u32,
176 /// 0-based page index this heading appears on.
177 pub page_index: usize,
178 /// Y position on the page (in points from top).
179 pub y_position: f64,
180}
181
182/// The complete result of laying out a document.
183#[derive(Debug, Clone)]
184pub struct LayoutResult {
185 /// Laid-out pages.
186 pub pages: Vec<PageFrame>,
187 /// Font data for all fonts used.
188 pub fonts: Vec<FontData>,
189 /// Optional document metadata for PDF output.
190 pub metadata: Option<DocumentMetadata>,
191 /// Outline/bookmark entries from headings.
192 pub outlines: Vec<OutlineEntry>,
193}