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