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
use super::backend::*;
use std::io::{Error, Write};

pub struct SvgBackend<W> {
    pub out: W,
    pub float_precision: usize
}

impl <W: Write> SvgBackend<W> {
    pub fn new(mut out: W) -> Result<SvgBackend<W>, Error> {
        write!(out, "<svg xmlns=\"http://www.w3.org/2000/svg\">\n")?;
        Ok(SvgBackend {
            out: out,
            float_precision: 2,
        })
    }
}

impl <W: Write> DrawBackend for SvgBackend<W> {
    type Error = Error;

    fn apply(&mut self, command: Command) -> Result<(), Error>{
        use super::backend::Command::*;

        match command {
            StartShape(options) => write!(&mut self.out, r#"    <path fill-rule="evenodd" d=""#),
            MoveTo { x , y } => write!(&mut self.out, "M{:.p$},{:.p$} ", x, y, p=self.float_precision),
            LineTo { x, y } => write!(&mut self.out, "L{:.p$},{:.p$} ", x, y, p=self.float_precision),
            CubicCurveTo { cx1, cy1, cx2, cy2, x, y, } => unimplemented!(),
            QuadraticCurveTo { cx, cy, x, y, } => unimplemented!(),
            ArcTo { rx, ry, rotation, large_arc, sweep, x, y, } => unimplemented!(),
            CloseShape => writeln!(&mut self.out, r#"z"/>"#),
            EndShape => writeln!(&mut self.out, r#""/>"#),
        }
    }
    fn close(mut self) -> Result<(), Error> {
        write!(&mut self.out, "</svg>")
    }
}

#[cfg(test)]
mod test {
    use super::super::*;
    use super::*;

    fn run_in_canvas<F>(f: F) -> String
    where F: FnOnce(&mut Canvas<SvgBackend<&mut Vec<u8>>>) -> Result<(), std::io::Error> {
        let mut buffer: Vec<u8> = Vec::new();
        {
            let mut canvas = Canvas::new(SvgBackend::new(&mut buffer).unwrap());
            f(&mut canvas).unwrap();
            canvas.close().unwrap();
        }
        return String::from_utf8(buffer).unwrap();
    }

    #[test]
    fn empty() {
        assert_eq!(run_in_canvas(|canvas| {
            Ok(())
        }).trim(), r#"
<svg xmlns="http://www.w3.org/2000/svg">
</svg>
        "#.trim())
    }

    #[test]
    fn empty_polygon() {
        assert_eq!(run_in_canvas(|canvas| {
            canvas.draw_closed_polygon(&[], DrawOptions::default())?;
            Ok(())
        }).trim(), r#"
<svg xmlns="http://www.w3.org/2000/svg">
</svg>
        "#.trim())
    }

    #[test]
    fn triangle_polygon() {
        assert_eq!(run_in_canvas(|canvas| {
            canvas.draw_closed_polygon(&[(0.0, 0.0), (0.0, 50.0), (50.0, 0.0)], DrawOptions::default())?;
            Ok(())
        }).trim(), r#"
<svg xmlns="http://www.w3.org/2000/svg">
    <path fill-rule="evenodd" d="M0,0 L0,50 L50,0 z"/>
</svg>
        "#.trim())
    }

    #[test]
    fn triangle_polygon_reversed() {
        assert_eq!(run_in_canvas(|canvas| {
            canvas.draw_closed_polygon(&[(50.0, 0.0), (0.0, 50.0), (0.0, 0.0)], DrawOptions::default())?;
            Ok(())
        }).trim(), r#"
<svg xmlns="http://www.w3.org/2000/svg">
    <path fill-rule="evenodd" d="M0,0 L0,50 L50,0 z"/>
</svg>
        "#.trim())
    }

    #[test]
    fn triangle_polygon_reversed_with_holes() {
        assert_eq!(run_in_canvas(|canvas| {
            canvas.draw_holy_polygon(
                vec![&[(50.0, 0.0), (0.0, 50.0), (0.0, 0.0)] as &[_]],
                vec![&[(30.0, 10.0), (10.0, 30.0), (10.0, 10.0)] as &[_]],
                DrawOptions::default()
            )
        }).trim(), r#"
<svg xmlns="http://www.w3.org/2000/svg">
    <path fill-rule="evenodd" d="M50,0 L0,0 L0,50 L50,0 M30,10 L10,30 L10,10 L30,10 "/>
</svg>
        "#.trim())
    }
}