1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
use {
    FuzzyEq,
    Transform,
    WriteBuffer,
    WriteOptions,
};

impl WriteBuffer for Transform {
    fn write_buf_opt(&self, opt: &WriteOptions, buf: &mut Vec<u8>) {
        if opt.simplify_transform_matrices {
            write_simplified_transform(self, opt, buf);
        } else {
            write_matrix_transform(self, opt, buf);
        }
    }
}

fn write_matrix_transform(ts: &Transform, opt: &WriteOptions, out: &mut Vec<u8>) {
    out.extend_from_slice(b"matrix(");
    ts.a.write_buf_opt(opt, out);
    opt.write_separator(out);
    ts.b.write_buf_opt(opt, out);
    opt.write_separator(out);
    ts.c.write_buf_opt(opt, out);
    opt.write_separator(out);
    ts.d.write_buf_opt(opt, out);
    opt.write_separator(out);
    ts.e.write_buf_opt(opt, out);
    opt.write_separator(out);
    ts.f.write_buf_opt(opt, out);
    out.push(b')');
}

fn write_simplified_transform(ts: &Transform, opt: &WriteOptions, out: &mut Vec<u8>) {
    if ts.is_translate() {
        out.extend_from_slice(b"translate(");
        ts.e.write_buf_opt(opt, out);

        if ts.f.fuzzy_ne(&0.0) {
            out.push(b' ');
            ts.f.write_buf_opt(opt, out);
        }

        out.push(b')');
    } else if ts.is_scale() {
        out.extend_from_slice(b"scale(");
        ts.a.write_buf_opt(opt, out);

        if ts.a.fuzzy_ne(&ts.d) {
            out.push(b' ');
            ts.d.write_buf_opt(opt, out);
        }

        out.push(b')');
    } else if !ts.has_translate() {
        let a = ts.get_rotate();
        let (sx, sy) = ts.get_scale();
        let (skx, sky) = ts.get_skew();

        if a.fuzzy_eq(&skx) && a.fuzzy_eq(&sky) && sx.fuzzy_eq(&1.0) && sy.fuzzy_eq(&1.0) {
            out.extend_from_slice(b"rotate(");
            a.write_buf_opt(opt, out);
            out.push(b')');
        } else {
            write_matrix_transform(ts, opt, out);
        }
    } else {
        write_matrix_transform(ts, opt, out);
    }
}

impl_display!(Transform);

#[cfg(test)]
mod tests {
    use std::str::FromStr;

    use super::*;
    use {
        WriteOptions,
        WriteBuffer,
        ListSeparator,
    };

    macro_rules! test {
        ($name:ident, $ts:expr, $simplify:expr, $result:expr) => (
            #[test]
            fn $name() {
                let mut opt = WriteOptions::default();
                opt.simplify_transform_matrices = $simplify;
                assert_eq!($ts.with_write_opt(&opt).to_string(), $result);
            }
        )
    }

    test!(write_1,
        Transform::default(), false,
        "matrix(1 0 0 1 0 0)"
    );

    test!(write_2,
        Transform::new(2.0, 0.0, 0.0, 3.0, 20.0, 30.0), false,
        "matrix(2 0 0 3 20 30)"
    );

    test!(write_3,
        Transform::new(1.0, 0.0, 0.0, 1.0, 20.0, 30.0), true,
        "translate(20 30)"
    );

    test!(write_4,
        Transform::new(1.0, 0.0, 0.0, 1.0, 20.0, 0.0), true,
        "translate(20)"
    );

    test!(write_5,
        Transform::new(2.0, 0.0, 0.0, 3.0, 0.0, 0.0), true,
        "scale(2 3)"
    );

    test!(write_6,
        Transform::new(2.0, 0.0, 0.0, 2.0, 0.0, 0.0), true,
        "scale(2)"
    );

    test!(write_7,
        Transform::from_str("rotate(30)").unwrap(), true,
        "rotate(30)"
    );

    test!(write_8,
        Transform::from_str("rotate(-45)").unwrap(), true,
        "rotate(-45)"
    );

    test!(write_9,
        Transform::from_str("rotate(33)").unwrap(), true,
        "rotate(33)"
    );

    test!(write_10,
        Transform::from_str("scale(-1)").unwrap(), true,
        "scale(-1)"
    );

    test!(write_11,
        Transform::from_str("scale(-1 1)").unwrap(), true,
        "scale(-1 1)"
    );

    test!(write_12,
        Transform::from_str("scale(1 -1)").unwrap(), true,
        "scale(1 -1)"
    );

    test!(write_13,
        Transform::new(1.0, 0.0, 0.0, 1.0, 20.0, 30.0), false,
        "matrix(1 0 0 1 20 30)"
    );

    #[test]
    fn write_14() {
        let mut opt = WriteOptions::default();
        opt.list_separator = ListSeparator::Comma;
        assert_eq!(Transform::default().with_write_opt(&opt).to_string(),
                   "matrix(1,0,0,1,0,0)");
    }

    #[test]
    fn write_15() {
        let mut opt = WriteOptions::default();
        opt.list_separator = ListSeparator::CommaSpace;
        assert_eq!(Transform::default().with_write_opt(&opt).to_string(),
                   "matrix(1, 0, 0, 1, 0, 0)");
    }
}