1use std::collections::HashMap;
4
5use oxml_chart::CT_ChartSpace;
6use oxml_layout::{
7 Diagnostic, Effect, GroupElement, MediaId, Paint, Path, Point, Rect, Stroke, Transform,
8};
9
10mod context;
11mod font;
12mod style;
13mod text;
14
15pub use context::{
16 BackgroundContent, BackgroundSource, EffectiveBackground, FlattenedItem, FlattenedSource,
17 ResolveCtx,
18};
19pub use style::{EffectiveShapeStyle, ResolveError};
20pub use text::{EffectiveListStyle, EffectiveTextProperties};
21
22#[derive(Clone, Debug, Default, Eq, PartialEq)]
24pub struct ScopedMediaIds {
25 pub slide: HashMap<String, MediaId>,
26 pub layout: HashMap<String, MediaId>,
27 pub master: HashMap<String, MediaId>,
28 pub media_content_types: HashMap<MediaId, String>,
30}
31
32impl ScopedMediaIds {
33 pub fn get(&self, source: FlattenedSource, relationship_id: &str) -> Option<MediaId> {
35 match source {
36 FlattenedSource::Slide => &self.slide,
37 FlattenedSource::Layout => &self.layout,
38 FlattenedSource::Master => &self.master,
39 FlattenedSource::Background => return None,
40 }
41 .get(relationship_id)
42 .copied()
43 }
44
45 pub fn content_type(&self, source: FlattenedSource, relationship_id: &str) -> Option<&str> {
47 let media_id = self.get(source, relationship_id)?;
48 self.media_content_types.get(&media_id).map(String::as_str)
49 }
50}
51
52#[derive(Clone, Debug, PartialEq)]
54pub enum ChartResource {
55 Parsed(Box<CT_ChartSpace>),
56 External(String),
57 MissingTarget(String),
58 Invalid(String),
59}
60
61#[derive(Clone, Debug, Default, PartialEq)]
63pub struct ScopedChartResources {
64 pub slide: HashMap<String, ChartResource>,
65 pub layout: HashMap<String, ChartResource>,
66 pub master: HashMap<String, ChartResource>,
67}
68
69impl ScopedChartResources {
70 pub fn get(&self, source: FlattenedSource, relationship_id: &str) -> Option<&ChartResource> {
72 match source {
73 FlattenedSource::Slide => &self.slide,
74 FlattenedSource::Layout => &self.layout,
75 FlattenedSource::Master => &self.master,
76 FlattenedSource::Background => return None,
77 }
78 .get(relationship_id)
79 }
80}
81
82#[derive(Clone, Debug, Default, Eq, PartialEq)]
84pub struct ScopedHyperlinkTargets {
85 pub slide: HashMap<String, String>,
86 pub layout: HashMap<String, String>,
87 pub master: HashMap<String, String>,
88}
89
90impl ScopedHyperlinkTargets {
91 pub fn get(&self, source: FlattenedSource, relationship_id: &str) -> Option<&str> {
93 match source {
94 FlattenedSource::Slide => &self.slide,
95 FlattenedSource::Layout => &self.layout,
96 FlattenedSource::Master => &self.master,
97 FlattenedSource::Background => return None,
98 }
99 .get(relationship_id)
100 .map(String::as_str)
101 }
102}
103
104#[derive(Clone, Debug, PartialEq)]
106pub struct ResolvedSlide {
107 pub size: (f64, f64),
109 pub background: Option<ResolvedBackground>,
110 pub shapes: Vec<ResolvedShape>,
112 pub diagnostics: Vec<Diagnostic>,
113}
114
115pub type ResolvedSlideTextDirections = Vec<Vec<Vec<oxml_layout::TextDirection>>>;
117
118#[derive(Clone, Debug, PartialEq)]
120pub enum ResolvedBackground {
121 Paint(Paint),
122 Image(ResolvedImage),
123}
124
125#[derive(Clone, Debug, PartialEq)]
127pub struct ResolvedShape {
128 pub group_transform: Transform,
130 pub bounds: Rect,
131 pub rotation_deg: f64,
132 pub flip_h: bool,
133 pub flip_v: bool,
134 pub geometry: ResolvedGeometry,
135 pub fill: Option<Paint>,
136 pub image_fill: Option<ResolvedImage>,
137 pub line: Option<Stroke>,
138 pub head_end: Option<ResolvedLineEnd>,
139 pub tail_end: Option<ResolvedLineEnd>,
140 pub shadow: Option<Effect>,
141 pub content: ResolvedContent,
142 pub unsupported: Option<&'static str>,
144}
145
146#[derive(Clone, Copy, Debug, Eq, PartialEq)]
148pub struct ResolvedLineEnd {
149 pub kind: ResolvedLineEndKind,
150 pub width: ResolvedLineEndSize,
151 pub length: ResolvedLineEndSize,
152}
153
154#[derive(Clone, Copy, Debug, Eq, PartialEq)]
156pub enum ResolvedLineEndKind {
157 Triangle,
158 Stealth,
159 Diamond,
160 Oval,
161 Arrow,
162}
163
164#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
166pub enum ResolvedLineEndSize {
167 Small,
168 #[default]
169 Medium,
170 Large,
171}
172
173#[derive(Clone, Debug, PartialEq)]
175pub enum ResolvedGeometry {
176 Rectangle,
177 Custom {
178 paths: Vec<Path>,
179 text_rect: Option<Rect>,
180 },
181 BoundsFallback,
182}
183
184#[derive(Clone, Debug, PartialEq)]
186pub enum ResolvedContent {
187 None,
188 Text(ResolvedTextBody),
189 Image(ResolvedImage),
190 Table(ResolvedTable),
191 Group(GroupElement),
192}
193
194#[derive(Clone, Debug, PartialEq)]
196pub struct ResolvedImage {
197 pub media: MediaId,
198 pub src_rect: Option<CropRect>,
199 pub placement: ResolvedImagePlacement,
200 pub dpi: Option<f64>,
201 pub rotate_with_shape: bool,
202}
203
204#[derive(Clone, Debug, PartialEq)]
206pub enum ResolvedImagePlacement {
207 Stretch { fill_rect: Option<CropRect> },
208 Tile(ResolvedTilePlacement),
209}
210
211impl Default for ResolvedImagePlacement {
212 fn default() -> Self {
213 Self::Stretch { fill_rect: None }
214 }
215}
216
217#[derive(Clone, Copy, Debug, PartialEq)]
219pub struct ResolvedTilePlacement {
220 pub translation: Point,
221 pub scale_x: f64,
222 pub scale_y: f64,
223 pub flip: ResolvedTileFlip,
224 pub alignment: ResolvedRectAlignment,
225}
226
227#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
229pub enum ResolvedTileFlip {
230 #[default]
231 None,
232 Horizontal,
233 Vertical,
234 Both,
235}
236
237#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
239pub enum ResolvedRectAlignment {
240 #[default]
241 TopLeft,
242 Top,
243 TopRight,
244 Left,
245 Center,
246 Right,
247 BottomLeft,
248 Bottom,
249 BottomRight,
250}
251
252#[derive(Clone, Copy, Debug, Default, PartialEq)]
254pub struct CropRect {
255 pub left: f64,
256 pub top: f64,
257 pub right: f64,
258 pub bottom: f64,
259}
260
261#[derive(Clone, Debug, PartialEq)]
263pub struct ResolvedTextBody {
264 pub insets: TextInsets,
265 pub anchor: TextAnchor,
266 pub wrap: bool,
267 pub vertical: TextDirection,
268 pub space_first_last_paragraph: bool,
269 pub autofit: ResolvedAutofit,
270 pub paragraphs: Vec<ResolvedParagraph>,
271}
272
273#[derive(Clone, Copy, Debug, Default, PartialEq)]
275pub struct TextInsets {
276 pub left: f64,
277 pub top: f64,
278 pub right: f64,
279 pub bottom: f64,
280}
281
282#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
283pub enum TextAnchor {
284 #[default]
285 Top,
286 Center,
287 Bottom,
288 Justified,
289 Distributed,
290}
291
292#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
293pub enum TextDirection {
294 #[default]
295 Horizontal,
296 Vertical,
297 Vertical270,
298 EastAsianVertical,
299 MongolianVertical,
300 WordArtVertical,
301 WordArtVerticalRtl,
302}
303
304#[derive(Clone, Copy, Debug, Default, PartialEq)]
305pub enum ResolvedAutofit {
306 #[default]
307 None,
308 Shape,
309 Normal {
310 font_scale: Option<f64>,
311 line_spacing_reduction: Option<f64>,
312 },
313}
314
315#[derive(Clone, Debug, Default, PartialEq)]
317pub struct ResolvedParagraph {
318 pub level: u8,
319 pub left_margin: f64,
320 pub right_margin: f64,
321 pub indent: f64,
322 pub alignment: ParagraphAlignment,
323 pub line_spacing: Option<ResolvedTextSpacing>,
324 pub space_before: Option<ResolvedTextSpacing>,
325 pub space_after: Option<ResolvedTextSpacing>,
326 pub bullet: Option<ResolvedBullet>,
327 pub end_style: ResolvedRunStyle,
328 pub runs: Vec<ResolvedTextRun>,
329}
330
331#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
332pub enum ParagraphAlignment {
333 #[default]
334 Left,
335 Center,
336 Right,
337 Justified,
338 Distributed,
339}
340
341#[derive(Clone, Debug, PartialEq)]
343pub enum ResolvedTextSpacing {
344 Percent(f64),
345 Points(f64),
346}
347
348#[derive(Clone, Debug, PartialEq)]
350pub enum ResolvedBulletSize {
351 Percent(f64),
352 Points(f64),
353}
354
355#[derive(Clone, Debug, PartialEq)]
356pub enum ResolvedBullet {
357 Character {
358 character: String,
359 font: Option<String>,
360 color: Option<oxml_layout::Color>,
361 size: Option<ResolvedBulletSize>,
362 },
363 AutoNumber {
364 scheme: String,
365 start_at: u32,
366 font: Option<String>,
367 color: Option<oxml_layout::Color>,
368 size: Option<ResolvedBulletSize>,
369 },
370}
371
372#[derive(Clone, Debug, PartialEq)]
374pub enum ResolvedTextRun {
375 Text {
376 text: String,
377 style: ResolvedRunStyle,
378 },
379 Break,
380 Field {
381 text: String,
382 field_type: Option<String>,
383 style: ResolvedRunStyle,
384 },
385}
386
387#[derive(Clone, Debug, Default, PartialEq)]
389pub struct ResolvedRunStyle {
390 pub font_size: Option<f64>,
391 pub bold: bool,
392 pub italic: bool,
393 pub all_caps: bool,
394 pub underline: bool,
395 pub strike: bool,
396 pub spacing: Option<f64>,
397 pub baseline: Option<f64>,
398 pub fill: Option<Paint>,
399 pub latin_typeface: Option<String>,
400 pub east_asian_typeface: Option<String>,
401 pub complex_script_typeface: Option<String>,
402 pub symbol_typeface: Option<String>,
403 pub hyperlink_url: Option<String>,
405}
406
407#[derive(Clone, Debug, Default, PartialEq)]
409pub struct ResolvedTable {
410 pub right_to_left: bool,
411 pub column_widths: Vec<f64>,
412 pub rows: Vec<ResolvedTableRow>,
413}
414
415#[derive(Clone, Debug, Default, PartialEq)]
416pub struct ResolvedTableRow {
417 pub height: f64,
418 pub cells: Vec<ResolvedTableCell>,
419}
420
421#[derive(Clone, Debug, PartialEq)]
422pub struct ResolvedTableCell {
423 pub text: Option<ResolvedTextBody>,
424 pub fill: Option<Paint>,
425 pub margins: TextInsets,
426 pub left: Option<ResolvedTableBorder>,
427 pub right: Option<ResolvedTableBorder>,
428 pub top: Option<ResolvedTableBorder>,
429 pub bottom: Option<ResolvedTableBorder>,
430 pub row_span: u32,
431 pub grid_span: u32,
432 pub horizontal_merge: bool,
433 pub vertical_merge: bool,
434}
435
436impl Default for ResolvedTableCell {
437 fn default() -> Self {
438 Self {
439 text: None,
440 fill: None,
441 margins: TextInsets::default(),
442 left: None,
443 right: None,
444 top: None,
445 bottom: None,
446 row_span: 1,
447 grid_span: 1,
448 horizontal_merge: false,
449 vertical_merge: false,
450 }
451 }
452}
453
454#[derive(Clone, Debug, Default, PartialEq)]
456pub struct ResolvedTableBorder {
457 pub stroke: Option<Stroke>,
458 pub priority: u8,
459}