Skip to main content

docx_rs/reader/
drawing.rs

1#![allow(clippy::single_match)]
2
3use std::io::Read;
4use std::str::FromStr;
5
6use crate::types::*;
7use crate::{DrawingPositionType, RelativeFromHType, RelativeFromVType};
8
9use super::*;
10
11fn read_position_h<R: Read>(
12    r: &mut EventReader<R>,
13    attrs: &[OwnedAttribute],
14) -> Result<(RelativeFromHType, i32), ReaderError> {
15    let mut offset: i32 = 0;
16    let mut relative_from_h = RelativeFromHType::default();
17
18    loop {
19        if let Some(h) = read(attrs, "relativeFrom") {
20            if let Ok(h) = RelativeFromHType::from_str(&h) {
21                relative_from_h = h;
22            }
23        }
24        let e = r.next();
25        match e {
26            Ok(XmlEvent::Characters(c)) => {
27                if let Ok(p) = f64::from_str(&c) {
28                    offset = p as i32;
29                }
30            }
31            Ok(XmlEvent::EndElement { name, .. }) => {
32                let e = WpXMLElement::from_str(&name.local_name).unwrap();
33                if e == WpXMLElement::PositionH {
34                    return Ok((relative_from_h, offset));
35                }
36            }
37            Err(_) => return Err(ReaderError::XMLReadError),
38            _ => {}
39        }
40    }
41}
42
43fn read_position_v<R: Read>(
44    r: &mut EventReader<R>,
45    attrs: &[OwnedAttribute],
46) -> Result<(RelativeFromVType, i32), ReaderError> {
47    let mut offset: i32 = 0;
48    let mut relative_from_v = RelativeFromVType::default();
49    loop {
50        if let Some(v) = read(attrs, "relativeFrom") {
51            if let Ok(v) = RelativeFromVType::from_str(&v) {
52                relative_from_v = v;
53            }
54        }
55
56        let e = r.next();
57        match e {
58            Ok(XmlEvent::Characters(c)) => {
59                if let Ok(p) = f64::from_str(&c) {
60                    offset = p as i32;
61                }
62            }
63            Ok(XmlEvent::EndElement { name, .. }) => {
64                let e = WpXMLElement::from_str(&name.local_name).unwrap();
65                if e == WpXMLElement::PositionV {
66                    return Ok((relative_from_v, offset));
67                }
68            }
69            Err(_) => return Err(ReaderError::XMLReadError),
70            _ => {}
71        }
72    }
73}
74
75fn read_textbox_content<R: Read>(
76    r: &mut EventReader<R>,
77    _attrs: &[OwnedAttribute],
78) -> Result<Vec<TextBoxContentChild>, ReaderError> {
79    let mut children = vec![];
80    loop {
81        let e = r.next();
82        match e {
83            Ok(XmlEvent::StartElement {
84                attributes, name, ..
85            }) => {
86                let e = XMLElement::from_str(&name.local_name).unwrap();
87                match e {
88                    XMLElement::Paragraph => {
89                        let p = Paragraph::read(r, &attributes)?;
90                        children.push(TextBoxContentChild::Paragraph(Box::new(p)));
91                        continue;
92                    }
93                    XMLElement::Table => {
94                        let t = Table::read(r, &attributes)?;
95                        children.push(TextBoxContentChild::Table(Box::new(t)));
96                        continue;
97                    }
98                    _ => {}
99                }
100            }
101            Ok(XmlEvent::EndElement { name, .. }) => {
102                let e = WpsXMLElement::from_str(&name.local_name).unwrap();
103                if e == WpsXMLElement::Txbx {
104                    return Ok(children);
105                }
106            }
107            Err(_) => return Err(ReaderError::XMLReadError),
108            _ => {}
109        }
110    }
111}
112
113impl ElementReader for Drawing {
114    fn read<R: Read>(
115        r: &mut EventReader<R>,
116        _attrs: &[OwnedAttribute],
117    ) -> Result<Self, ReaderError> {
118        let mut drawing = Drawing::new();
119        let mut drawing_position_type = DrawingPositionType::Inline;
120
121        let mut simple_pos = false;
122        let mut simple_pos_x = 0;
123        let mut simple_pos_y = 0;
124        let mut layout_in_cell = true;
125        let mut relative_height = 0;
126        let mut position_h = 0;
127        let mut position_v = 0;
128        let mut relative_from_h = RelativeFromHType::default();
129        let mut relative_from_v = RelativeFromVType::default();
130        let mut allow_overlap = true;
131        let mut dist_t = 0;
132        let mut dist_b = 0;
133        let mut dist_l = 0;
134        let mut dist_r = 0;
135
136        loop {
137            let e = r.next();
138            match e {
139                Ok(XmlEvent::StartElement {
140                    name, attributes, ..
141                }) => {
142                    // wp:
143                    if let Ok(wpe) = WpXMLElement::from_str(&name.local_name) {
144                        match wpe {
145                            WpXMLElement::Anchor => {
146                                drawing_position_type = DrawingPositionType::Anchor;
147                                if let Some(v) = read(&attributes, "simplePos") {
148                                    if !is_false(&v) {
149                                        simple_pos = true;
150                                    }
151                                }
152                                if let Some(d) = read(&attributes, "distT") {
153                                    if let Ok(d) = f64::from_str(&d) {
154                                        dist_t = d as i32;
155                                    }
156                                }
157                                if let Some(d) = read(&attributes, "distB") {
158                                    if let Ok(d) = f64::from_str(&d) {
159                                        dist_b = d as i32;
160                                    }
161                                }
162                                if let Some(d) = read(&attributes, "distL") {
163                                    if let Ok(d) = f64::from_str(&d) {
164                                        dist_l = d as i32;
165                                    }
166                                }
167                                if let Some(d) = read(&attributes, "distR") {
168                                    if let Ok(d) = f64::from_str(&d) {
169                                        dist_r = d as i32;
170                                    }
171                                }
172                                if let Some(d) = read(&attributes, "layoutInCell") {
173                                    if is_false(&d) {
174                                        layout_in_cell = false;
175                                    }
176                                }
177                                if let Some(d) = read(&attributes, "relativeHeight") {
178                                    if let Ok(d) = f64::from_str(&d) {
179                                        relative_height = d as u32;
180                                    }
181                                }
182                                if let Some(d) = read(&attributes, "allowOverlap") {
183                                    if is_false(&d) {
184                                        allow_overlap = false;
185                                    }
186                                }
187                            }
188                            WpXMLElement::Inline => {
189                                drawing_position_type = DrawingPositionType::Inline;
190                                if let Some(d) = read(&attributes, "distT") {
191                                    if let Ok(d) = f64::from_str(&d) {
192                                        dist_t = d as i32;
193                                    }
194                                }
195                                if let Some(d) = read(&attributes, "distB") {
196                                    if let Ok(d) = f64::from_str(&d) {
197                                        dist_b = d as i32;
198                                    }
199                                }
200                                if let Some(d) = read(&attributes, "distL") {
201                                    if let Ok(d) = f64::from_str(&d) {
202                                        dist_l = d as i32;
203                                    }
204                                }
205                                if let Some(d) = read(&attributes, "distR") {
206                                    if let Ok(d) = i32::from_str(&d) {
207                                        dist_r = d;
208                                    }
209                                }
210                            }
211                            WpXMLElement::SimplePos => {
212                                if let Some(x) = read(&attributes, "x") {
213                                    if let Ok(x) = f64::from_str(&x) {
214                                        simple_pos_x = x as i32;
215                                    }
216                                }
217                                if let Some(y) = read(&attributes, "y") {
218                                    if let Ok(y) = f64::from_str(&y) {
219                                        simple_pos_y = y as i32;
220                                    }
221                                }
222                            }
223                            WpXMLElement::PositionH => {
224                                if let Ok(p) = read_position_h(r, &attributes) {
225                                    relative_from_h = p.0;
226                                    position_h = p.1;
227                                }
228                            }
229                            WpXMLElement::PositionV => {
230                                if let Ok(p) = read_position_v(r, &attributes) {
231                                    relative_from_v = p.0;
232                                    position_v = p.1;
233                                }
234                            }
235                            _ => {}
236                        }
237                    }
238                    // pic:
239                    if let Ok(PicXMLElement::Pic) = PicXMLElement::from_str(&name.local_name) {
240                        if let Ok(mut pic) = Pic::read(r, &attributes) {
241                            pic.position_type = drawing_position_type;
242                            pic.simple_pos = simple_pos;
243                            pic.simple_pos_x = simple_pos_x;
244                            pic.simple_pos_y = simple_pos_y;
245                            pic.layout_in_cell = layout_in_cell;
246                            pic.relative_height = relative_height;
247                            pic.allow_overlap = allow_overlap;
248                            pic.dist_r = dist_r;
249                            pic.dist_t = dist_t;
250                            pic.dist_b = dist_b;
251                            pic.dist_l = dist_l;
252                            pic.dist_r = dist_r;
253                            pic.relative_from_h = relative_from_h;
254                            pic.relative_from_v = relative_from_v;
255                            pic.position_v = DrawingPosition::Offset(position_v);
256                            pic.position_h = DrawingPosition::Offset(position_h);
257                            drawing = drawing.pic(pic);
258                        }
259                    }
260
261                    // wps:
262                    if let Ok(WpsXMLElement::Txbx) = WpsXMLElement::from_str(&name.local_name) {
263                        if let Ok(children) = read_textbox_content(r, &attributes) {
264                            let mut text_box = TextBox::new();
265                            text_box.position_type = drawing_position_type;
266                            text_box.simple_pos = simple_pos;
267                            text_box.simple_pos_x = simple_pos_x;
268                            text_box.simple_pos_y = simple_pos_y;
269                            text_box.layout_in_cell = layout_in_cell;
270                            text_box.relative_height = relative_height;
271                            text_box.allow_overlap = allow_overlap;
272                            text_box.dist_r = dist_r;
273                            text_box.dist_t = dist_t;
274                            text_box.dist_b = dist_b;
275                            text_box.dist_l = dist_l;
276                            text_box.dist_r = dist_r;
277                            text_box.relative_from_h = relative_from_h;
278                            text_box.relative_from_v = relative_from_v;
279                            text_box.position_v = DrawingPosition::Offset(position_v);
280                            text_box.position_h = DrawingPosition::Offset(position_h);
281                            text_box.children = children;
282                            drawing = drawing.text_box(text_box);
283                        }
284                    }
285                }
286                Ok(XmlEvent::EndElement { name, .. }) => {
287                    let e = XMLElement::from_str(&name.local_name).unwrap();
288                    if e == XMLElement::Drawing {
289                        return Ok(drawing);
290                    }
291                }
292                Err(_) => return Err(ReaderError::XMLReadError),
293                _ => {}
294            }
295        }
296    }
297}