1 | // Copyright 2018 the SVG Types Authors |
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT |
3 | |
4 | use crate::{Error, Stream}; |
5 | |
6 | /// Representation of the `align` value of the [`preserveAspectRatio`] attribute. |
7 | /// |
8 | /// [`preserveAspectRatio`]: https://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute |
9 | #[allow (missing_docs)] |
10 | #[derive (Clone, Copy, PartialEq, Eq, Debug)] |
11 | pub enum Align { |
12 | None, |
13 | XMinYMin, |
14 | XMidYMin, |
15 | XMaxYMin, |
16 | XMinYMid, |
17 | XMidYMid, |
18 | XMaxYMid, |
19 | XMinYMax, |
20 | XMidYMax, |
21 | XMaxYMax, |
22 | } |
23 | |
24 | /// Representation of the [`preserveAspectRatio`] attribute. |
25 | /// |
26 | /// SVG 2 removed the `defer` keyword, but we still support it. |
27 | /// |
28 | /// [`preserveAspectRatio`]: https://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute |
29 | #[derive (Clone, Copy, PartialEq, Eq, Debug)] |
30 | pub struct AspectRatio { |
31 | /// `<defer>` value. |
32 | /// |
33 | /// Set to `true` when `defer` value is present. |
34 | pub defer: bool, |
35 | /// `<align>` value. |
36 | pub align: Align, |
37 | /// `<meetOrSlice>` value. |
38 | /// |
39 | /// - Set to `true` when `slice` value is present. |
40 | /// - Set to `false` when `meet` value is present or value is not set at all. |
41 | pub slice: bool, |
42 | } |
43 | |
44 | impl std::str::FromStr for AspectRatio { |
45 | type Err = Error; |
46 | |
47 | fn from_str(text: &str) -> Result<Self, Error> { |
48 | let mut s = Stream::from(text); |
49 | |
50 | s.skip_spaces(); |
51 | |
52 | let defer = s.starts_with(b"defer" ); |
53 | if defer { |
54 | s.advance(5); |
55 | s.consume_byte(b' ' )?; |
56 | s.skip_spaces(); |
57 | } |
58 | |
59 | let start = s.pos(); |
60 | let align = s.consume_ascii_ident(); |
61 | let align = match align { |
62 | "none" => Align::None, |
63 | "xMinYMin" => Align::XMinYMin, |
64 | "xMidYMin" => Align::XMidYMin, |
65 | "xMaxYMin" => Align::XMaxYMin, |
66 | "xMinYMid" => Align::XMinYMid, |
67 | "xMidYMid" => Align::XMidYMid, |
68 | "xMaxYMid" => Align::XMaxYMid, |
69 | "xMinYMax" => Align::XMinYMax, |
70 | "xMidYMax" => Align::XMidYMax, |
71 | "xMaxYMax" => Align::XMaxYMax, |
72 | _ => return Err(Error::UnexpectedData(s.calc_char_pos_at(start))), |
73 | }; |
74 | |
75 | s.skip_spaces(); |
76 | |
77 | let mut slice = false; |
78 | if !s.at_end() { |
79 | let start = s.pos(); |
80 | let v = s.consume_ascii_ident(); |
81 | match v { |
82 | "meet" => {} |
83 | "slice" => slice = true, |
84 | "" => {} |
85 | _ => return Err(Error::UnexpectedData(s.calc_char_pos_at(start))), |
86 | }; |
87 | } |
88 | |
89 | Ok(AspectRatio { |
90 | defer, |
91 | align, |
92 | slice, |
93 | }) |
94 | } |
95 | } |
96 | |
97 | impl Default for AspectRatio { |
98 | #[inline ] |
99 | fn default() -> Self { |
100 | AspectRatio { |
101 | defer: false, |
102 | align: Align::XMidYMid, |
103 | slice: false, |
104 | } |
105 | } |
106 | } |
107 | |
108 | #[rustfmt::skip] |
109 | #[cfg (test)] |
110 | mod tests { |
111 | use super::*; |
112 | use std::str::FromStr; |
113 | |
114 | macro_rules! test { |
115 | ($name:ident, $text:expr, $result:expr) => ( |
116 | #[test] |
117 | fn $name() { |
118 | let v = AspectRatio::from_str($text).unwrap(); |
119 | assert_eq!(v, $result); |
120 | } |
121 | ) |
122 | } |
123 | |
124 | test !(parse_1, "none" , AspectRatio { |
125 | defer: false, |
126 | align: Align::None, |
127 | slice: false, |
128 | }); |
129 | |
130 | test !(parse_2, "defer none" , AspectRatio { |
131 | defer: true, |
132 | align: Align::None, |
133 | slice: false, |
134 | }); |
135 | |
136 | test !(parse_3, "xMinYMid" , AspectRatio { |
137 | defer: false, |
138 | align: Align::XMinYMid, |
139 | slice: false, |
140 | }); |
141 | |
142 | test !(parse_4, "xMinYMid slice" , AspectRatio { |
143 | defer: false, |
144 | align: Align::XMinYMid, |
145 | slice: true, |
146 | }); |
147 | |
148 | test !(parse_5, "xMinYMid meet" , AspectRatio { |
149 | defer: false, |
150 | align: Align::XMinYMid, |
151 | slice: false, |
152 | }); |
153 | } |
154 | |