Skip to main content

docx_rs/reader/
run_property.rs

1use std::io::Read;
2use std::str::FromStr;
3
4use crate::{ThemeColor, VertAlignType};
5
6use super::*;
7
8// Parse a `<w:color>` element, including the optional theme attributes.
9//
10// Attributes are read by local name rather than position: Word may emit them
11// in any order, and a theme-only color can omit `w:val` (we fall back to
12// "auto"). Unknown themeColor tokens degrade to `ThemeColor::Unsupported`
13// via its `FromStr`, so a future ST_ThemeColor value never breaks reading.
14fn read_color(rp: RunProperty, attributes: &[OwnedAttribute]) -> RunProperty {
15    let val = read(attributes, "val").unwrap_or_else(|| "auto".to_string());
16    let mut rp = rp.color(val);
17    if let Some(tc) = read(attributes, "themeColor") {
18        if let Ok(theme) = ThemeColor::from_str(&tc) {
19            rp = rp.theme_color(theme);
20        }
21    }
22    if let Some(ts) = read(attributes, "themeShade") {
23        rp = rp.theme_shade(ts);
24    }
25    if let Some(tt) = read(attributes, "themeTint") {
26        rp = rp.theme_tint(tt);
27    }
28    rp
29}
30
31fn read_run_fonts(attributes: &[OwnedAttribute]) -> Result<RunFonts, ReaderError> {
32    let mut f = RunFonts::new();
33    for a in attributes {
34        let local_name = &a.name.local_name;
35        match local_name.as_str() {
36            "asciiTheme" => {
37                f = f.ascii_theme(&a.value);
38            }
39            "eastAsiaTheme" => {
40                f = f.east_asia_theme(&a.value);
41            }
42            "hAnsiTheme" => {
43                f = f.hi_ansi_theme(&a.value);
44            }
45            "cstheme" => {
46                f = f.cs_theme(&a.value);
47            }
48            "ascii" => {
49                f = f.ascii(&a.value);
50            }
51            "eastAsia" => {
52                f = f.east_asia(&a.value);
53            }
54            "hAnsi" => {
55                f = f.hi_ansi(&a.value);
56            }
57            "cs" => {
58                f = f.cs(&a.value);
59            }
60            "hint" => {
61                f = f.hint(&a.value);
62            }
63            _ => {}
64        }
65    }
66    Ok(f)
67}
68
69impl ElementReader for RunProperty {
70    fn read<R: Read>(
71        r: &mut EventReader<R>,
72        _attrs: &[OwnedAttribute],
73    ) -> Result<Self, ReaderError> {
74        let mut rp = RunProperty::new();
75        loop {
76            let e = r.next_event();
77            match e {
78                Ok(XmlEvent::StartElement {
79                    attributes, name, ..
80                }) => {
81                    let e = XMLElement::from_str(&name.local_name).unwrap();
82
83                    ignore::ignore_element(e.clone(), XMLElement::RunPropertyChange, r);
84
85                    match e {
86                        XMLElement::RunStyle => {
87                            if let Some(v) = read_val(&attributes) {
88                                rp = rp.style(&v);
89                            }
90                        }
91                        XMLElement::Bold => {
92                            if !read_bool(&attributes) {
93                                rp = rp.disable_bold();
94                                continue;
95                            }
96                            rp = rp.bold();
97                        }
98                        XMLElement::Caps => {
99                            if !read_bool(&attributes) {
100                                rp.caps = Some(Caps::new().disable());
101                                continue;
102                            }
103                            rp = rp.caps();
104                        }
105                        XMLElement::PTab => {
106                            if let Ok(v) = PositionalTab::read(r, &attributes) {
107                                rp = rp.ptab(v)
108                            }
109                        }
110                        XMLElement::Highlight => rp = rp.highlight(attributes[0].value.clone()),
111                        XMLElement::Strike => {
112                            if !read_bool(&attributes) {
113                                rp.strike = Some(Strike::new().disable());
114                                continue;
115                            }
116                            rp = rp.strike();
117                        }
118                        XMLElement::Dstrike => {
119                            if !read_bool(&attributes) {
120                                rp.dstrike = Some(Dstrike::new().disable());
121                                continue;
122                            }
123                            rp = rp.dstrike();
124                        }
125                        XMLElement::VertAlign => {
126                            if let Ok(v) = VertAlignType::from_str(&attributes[0].value) {
127                                rp = rp.vert_align(v)
128                            }
129                        }
130                        XMLElement::Color => rp = read_color(rp, &attributes),
131                        XMLElement::Size => {
132                            rp = rp.size(f64::from_str(&attributes[0].value)? as usize)
133                        }
134                        XMLElement::Spacing => {
135                            if let Some(v) = read_val(&attributes) {
136                                if let Ok(s) = f64::from_str(&v) {
137                                    rp = rp.spacing(s as i32)
138                                }
139                            }
140                        }
141                        XMLElement::FitText => {
142                            if let Some(v) = read_val(&attributes) {
143                                if let Ok(val) = usize::from_str(&v) {
144                                    let id = read(&attributes, "id")
145                                        .and_then(|id| u32::from_str(&id).ok());
146                                    rp = rp.fit_text(val, id);
147                                }
148                            }
149                        }
150                        XMLElement::RunFonts => {
151                            if let Ok(f) = read_run_fonts(&attributes) {
152                                rp = rp.fonts(f);
153                            }
154                        }
155                        XMLElement::Underline => rp = rp.underline(attributes[0].value.clone()),
156                        XMLElement::Italic => {
157                            if !read_bool(&attributes) {
158                                rp = rp.disable_italic();
159                                continue;
160                            }
161                            rp = rp.italic();
162                        }
163                        XMLElement::Shading => {
164                            if let Ok(shd) = Shading::read(r, &attributes) {
165                                rp = rp.shading(shd);
166                            }
167                        }
168                        XMLElement::Vanish => rp = rp.vanish(),
169                        XMLElement::SpecVanish => rp = rp.spec_vanish(),
170                        XMLElement::TextBorder => {
171                            if let Ok(attr) = read_border(&attributes) {
172                                let mut border = TextBorder::new()
173                                    .border_type(attr.border_type)
174                                    .color(attr.color);
175                                if let Some(size) = attr.size {
176                                    border = border.size(size as usize);
177                                };
178                                rp = rp.text_border(border);
179                                continue;
180                            }
181                        }
182                        XMLElement::Insert => {
183                            if let Ok(ins) = Insert::read(r, &attributes) {
184                                rp = rp.insert(ins);
185                            }
186                        }
187                        XMLElement::Delete => {
188                            if let Ok(del) = Delete::read(r, &attributes) {
189                                rp = rp.delete(del);
190                            }
191                        }
192                        _ => {}
193                    }
194                }
195                Ok(XmlEvent::EndElement { name, .. }) => {
196                    let e = XMLElement::from_str(&name.local_name).unwrap();
197                    if e == XMLElement::RunProperty {
198                        return Ok(rp);
199                    }
200                }
201                Err(_) => return Err(ReaderError::XMLReadError),
202                _ => {}
203            }
204        }
205    }
206}