docx_rs/reader/
drawing.rs

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