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, inherited_xfrm,
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 unresolved_member_count: usize,
136 pub shapes: Vec<ResolvedShape>,
138 pub diagnostics: Vec<Diagnostic>,
139}
140
141pub type ResolvedSlideTextDirections = Vec<Vec<Vec<oxml_layout::TextDirection>>>;
143
144#[derive(Clone, Debug, PartialEq)]
146pub enum ResolvedBackground {
147 Paint(Paint),
148 Image(ResolvedImage),
149}
150
151#[derive(Clone, Debug, PartialEq)]
153pub struct ResolvedShape {
154 pub group_transform: Transform,
156 pub bounds: Rect,
157 pub rotation_deg: f64,
158 pub flip_h: bool,
159 pub flip_v: bool,
160 pub geometry: ResolvedGeometry,
161 pub fill: Option<Paint>,
162 pub image_fill: Option<ResolvedImage>,
163 pub line: Option<Stroke>,
164 pub head_end: Option<ResolvedLineEnd>,
165 pub tail_end: Option<ResolvedLineEnd>,
166 pub shadow: Option<Effect>,
167 pub content: ResolvedContent,
168 pub unsupported: Option<&'static str>,
170}
171
172#[derive(Clone, Copy, Debug, Eq, PartialEq)]
174pub struct ResolvedLineEnd {
175 pub kind: ResolvedLineEndKind,
176 pub width: ResolvedLineEndSize,
177 pub length: ResolvedLineEndSize,
178}
179
180#[derive(Clone, Copy, Debug, Eq, PartialEq)]
182pub enum ResolvedLineEndKind {
183 Triangle,
184 Stealth,
185 Diamond,
186 Oval,
187 Arrow,
188}
189
190#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
192pub enum ResolvedLineEndSize {
193 Small,
194 #[default]
195 Medium,
196 Large,
197}
198
199#[derive(Clone, Debug, PartialEq)]
201pub enum ResolvedGeometry {
202 Rectangle,
203 Custom {
204 paths: Vec<Path>,
205 text_rect: Option<Rect>,
206 },
207 BoundsFallback,
208}
209
210#[derive(Clone, Debug, PartialEq)]
212pub enum ResolvedContent {
213 None,
214 Text(ResolvedTextBody),
215 Image(ResolvedImage),
216 Table(ResolvedTable),
217 Group(GroupElement),
218}
219
220#[derive(Clone, Debug, PartialEq)]
222pub struct ResolvedImage {
223 pub media: MediaId,
224 pub src_rect: Option<CropRect>,
225 pub placement: ResolvedImagePlacement,
226 pub dpi: Option<f64>,
227 pub rotate_with_shape: bool,
228 pub opacity: f64,
230}
231
232#[derive(Clone, Debug, PartialEq)]
234pub enum ResolvedImagePlacement {
235 Stretch { fill_rect: Option<CropRect> },
236 Tile(ResolvedTilePlacement),
237}
238
239impl Default for ResolvedImagePlacement {
240 fn default() -> Self {
241 Self::Stretch { fill_rect: None }
242 }
243}
244
245#[derive(Clone, Copy, Debug, PartialEq)]
247pub struct ResolvedTilePlacement {
248 pub translation: Point,
249 pub scale_x: f64,
250 pub scale_y: f64,
251 pub flip: ResolvedTileFlip,
252 pub alignment: ResolvedRectAlignment,
253}
254
255#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
257pub enum ResolvedTileFlip {
258 #[default]
259 None,
260 Horizontal,
261 Vertical,
262 Both,
263}
264
265#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
267pub enum ResolvedRectAlignment {
268 #[default]
269 TopLeft,
270 Top,
271 TopRight,
272 Left,
273 Center,
274 Right,
275 BottomLeft,
276 Bottom,
277 BottomRight,
278}
279
280#[derive(Clone, Copy, Debug, Default, PartialEq)]
282pub struct CropRect {
283 pub left: f64,
284 pub top: f64,
285 pub right: f64,
286 pub bottom: f64,
287}
288
289#[derive(Clone, Debug, PartialEq)]
291pub struct ResolvedTextBody {
292 pub insets: TextInsets,
293 pub anchor: TextAnchor,
294 pub wrap: bool,
295 pub vertical: TextDirection,
296 pub space_first_last_paragraph: bool,
297 pub autofit: ResolvedAutofit,
298 pub paragraphs: Vec<ResolvedParagraph>,
299}
300
301#[derive(Clone, Copy, Debug, Default, PartialEq)]
303pub struct TextInsets {
304 pub left: f64,
305 pub top: f64,
306 pub right: f64,
307 pub bottom: f64,
308}
309
310#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
311pub enum TextAnchor {
312 #[default]
313 Top,
314 Center,
315 Bottom,
316 Justified,
317 Distributed,
318}
319
320#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
321pub enum TextDirection {
322 #[default]
323 Horizontal,
324 Vertical,
325 Vertical270,
326 EastAsianVertical,
327 MongolianVertical,
328 WordArtVertical,
329 WordArtVerticalRtl,
330}
331
332#[derive(Clone, Copy, Debug, Default, PartialEq)]
333pub enum ResolvedAutofit {
334 #[default]
335 None,
336 Shape,
337 Normal {
338 font_scale: Option<f64>,
339 line_spacing_reduction: Option<f64>,
340 },
341}
342
343#[derive(Clone, Debug, Default, PartialEq)]
345pub struct ResolvedParagraph {
346 pub level: u8,
347 pub left_margin: f64,
348 pub right_margin: f64,
349 pub indent: f64,
350 pub alignment: ParagraphAlignment,
351 pub line_spacing: Option<ResolvedTextSpacing>,
352 pub space_before: Option<ResolvedTextSpacing>,
353 pub space_after: Option<ResolvedTextSpacing>,
354 pub bullet: Option<ResolvedBullet>,
355 pub end_style: ResolvedRunStyle,
356 pub runs: Vec<ResolvedTextRun>,
357}
358
359#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
360pub enum ParagraphAlignment {
361 #[default]
362 Left,
363 Center,
364 Right,
365 Justified,
366 Distributed,
367}
368
369#[derive(Clone, Debug, PartialEq)]
371pub enum ResolvedTextSpacing {
372 Percent(f64),
373 Points(f64),
374}
375
376#[derive(Clone, Debug, PartialEq)]
378pub enum ResolvedBulletSize {
379 Percent(f64),
380 Points(f64),
381}
382
383#[derive(Clone, Debug, PartialEq)]
384pub enum ResolvedBullet {
385 Character {
386 character: String,
387 font: Option<String>,
388 color: Option<oxml_layout::Color>,
389 size: Option<ResolvedBulletSize>,
390 },
391 AutoNumber {
392 scheme: String,
393 start_at: u32,
394 font: Option<String>,
395 color: Option<oxml_layout::Color>,
396 size: Option<ResolvedBulletSize>,
397 },
398}
399
400#[derive(Clone, Debug, PartialEq)]
402pub enum ResolvedTextRun {
403 Text {
404 text: String,
405 style: ResolvedRunStyle,
406 },
407 Break,
408 Field {
409 text: String,
410 field_type: Option<String>,
411 style: ResolvedRunStyle,
412 },
413}
414
415#[derive(Clone, Debug, Default, PartialEq)]
417pub struct ResolvedRunStyle {
418 pub font_size: Option<f64>,
419 pub bold: bool,
420 pub italic: bool,
421 pub all_caps: bool,
422 pub small_caps: bool,
423 pub language: Option<String>,
425 pub highlight: Option<oxml_layout::Color>,
426 pub underline: bool,
427 pub strike: bool,
428 pub spacing: Option<f64>,
429 pub baseline: Option<f64>,
430 pub fill: Option<Paint>,
431 pub latin_typeface: Option<String>,
432 pub east_asian_typeface: Option<String>,
433 pub complex_script_typeface: Option<String>,
434 pub symbol_typeface: Option<String>,
435 pub hyperlink_url: Option<String>,
437}
438
439#[derive(Clone, Debug, Default, PartialEq)]
441pub struct ResolvedTable {
442 pub right_to_left: bool,
443 pub column_widths: Vec<f64>,
444 pub rows: Vec<ResolvedTableRow>,
445 pub background: Option<Paint>,
448}
449
450#[derive(Clone, Debug, Default, PartialEq)]
451pub struct ResolvedTableRow {
452 pub height: f64,
453 pub cells: Vec<ResolvedTableCell>,
454}
455
456#[derive(Clone, Debug, PartialEq)]
457pub struct ResolvedTableCell {
458 pub text: Option<ResolvedTextBody>,
459 pub fill: Option<Paint>,
460 pub margins: TextInsets,
461 pub left: Option<ResolvedTableBorder>,
462 pub right: Option<ResolvedTableBorder>,
463 pub top: Option<ResolvedTableBorder>,
464 pub bottom: Option<ResolvedTableBorder>,
465 pub row_span: u32,
466 pub grid_span: u32,
467 pub horizontal_merge: bool,
468 pub vertical_merge: bool,
469}
470
471impl Default for ResolvedTableCell {
472 fn default() -> Self {
473 Self {
474 text: None,
475 fill: None,
476 margins: TextInsets::default(),
477 left: None,
478 right: None,
479 top: None,
480 bottom: None,
481 row_span: 1,
482 grid_span: 1,
483 horizontal_merge: false,
484 vertical_merge: false,
485 }
486 }
487}
488
489#[derive(Clone, Debug, Default, PartialEq)]
491pub struct ResolvedTableBorder {
492 pub stroke: Option<Stroke>,
493 pub priority: u8,
494}