1
1
use gio::prelude::*;
2

            
3
use rsvg::tests_only::{SharedImageSurface, SurfaceType};
4
use rsvg::{CairoRenderer, RenderingError};
5

            
6
use rsvg::test_utils::load_svg;
7
use rsvg::test_utils::reference_utils::{Compare, Evaluate, Reference};
8

            
9
#[test]
10
2
fn has_element_with_id_works() {
11
1
    let svg = load_svg(
12
        br#"<?xml version="1.0" encoding="UTF-8"?>
13
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
14
  <rect id="foo" x="10" y="10" width="30" height="30"/>
15
</svg>
16
"#,
17
    )
18
    .unwrap();
19

            
20
1
    assert!(svg.has_element_with_id("#foo").unwrap());
21
1
    assert!(!svg.has_element_with_id("#bar").unwrap());
22

            
23
1
    assert!(matches!(
24
1
        svg.has_element_with_id(""),
25
        Err(RenderingError::InvalidId(_))
26
    ));
27

            
28
1
    assert!(matches!(
29
1
        svg.has_element_with_id("not a fragment"),
30
        Err(RenderingError::InvalidId(_))
31
    ));
32

            
33
1
    assert!(matches!(
34
1
        svg.has_element_with_id("notfragment#fragment"),
35
        Err(RenderingError::InvalidId(_))
36
    ));
37
2
}
38

            
39
#[test]
40
2
fn render_layer() {
41
1
    let svg = load_svg(
42
        br##"<?xml version="1.0" encoding="UTF-8"?>
43
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
44
  <rect id="foo" x="10" y="10" width="30" height="30" fill="#00ff00"/>
45
  <rect id="bar" x="20" y="20" width="30" height="30" fill="#0000ff"/>
46
</svg>
47
"##,
48
    )
49
    .unwrap();
50

            
51
1
    let renderer = CairoRenderer::new(&svg);
52

            
53
1
    let output = cairo::ImageSurface::create(cairo::Format::ARgb32, 300, 300).unwrap();
54

            
55
    let res = {
56
1
        let cr = cairo::Context::new(&output).expect("Failed to create cairo context");
57
1
        let viewport = cairo::Rectangle::new(100.0, 100.0, 100.0, 100.0);
58

            
59
1
        renderer.render_layer(&cr, Some("#bar"), &viewport)
60
1
    };
61

            
62
1
    let output_surf = res
63
2
        .map(|_| SharedImageSurface::wrap(output, SurfaceType::SRgb).unwrap())
64
        .unwrap();
65

            
66
1
    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 300, 300).unwrap();
67

            
68
    {
69
1
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");
70

            
71
1
        cr.translate(100.0, 100.0);
72

            
73
1
        cr.rectangle(20.0, 20.0, 30.0, 30.0);
74
1
        cr.set_source_rgba(0.0, 0.0, 1.0, 1.0);
75
1
        cr.fill().unwrap();
76
1
    }
77

            
78
1
    Reference::from_surface(reference_surf)
79
        .compare(&output_surf)
80
1
        .evaluate(&output_surf, "render_layer");
81
2
}
82

            
83
#[test]
84
2
fn untransformed_element() {
85
    // This has a rectangle inside a transformed group.  The rectangle
86
    // inherits its stroke-width from the group.
87
    //
88
    // The idea is that we'll be able to extract the geometry of the rectangle
89
    // as if it were not transformed by its ancestors, but still retain the
90
    // cascade from the ancestors.
91
1
    let svg = load_svg(
92
        br##"<?xml version="1.0" encoding="UTF-8"?>
93
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
94
  <g transform="rotate(45)" stroke-width="10" stroke="#000000">
95
    <rect id="foo" x="10" y="20" width="30" height="40" fill="#0000ff"/>
96
  </g>
97
</svg>
98
"##,
99
    )
100
    .unwrap();
101

            
102
1
    let renderer = CairoRenderer::new(&svg);
103

            
104
    /* Measuring */
105

            
106
1
    let (ink_r, logical_r) = renderer.geometry_for_element(Some("#foo")).unwrap();
107

            
108
1
    assert_eq!(ink_r, cairo::Rectangle::new(0.0, 0.0, 40.0, 50.0));
109

            
110
1
    assert_eq!(logical_r, cairo::Rectangle::new(5.0, 5.0, 30.0, 40.0));
111

            
112
    /* Rendering */
113

            
114
1
    let output = cairo::ImageSurface::create(cairo::Format::ARgb32, 300, 300).unwrap();
115

            
116
    let res = {
117
1
        let cr = cairo::Context::new(&output).expect("Failed to create cairo context");
118
1
        let viewport = cairo::Rectangle::new(100.0, 100.0, 100.0, 100.0);
119

            
120
1
        renderer.render_element(&cr, Some("#foo"), &viewport)
121
1
    };
122

            
123
1
    let output_surf = res
124
2
        .map(|_| SharedImageSurface::wrap(output, SurfaceType::SRgb).unwrap())
125
        .unwrap();
126

            
127
1
    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 300, 300).unwrap();
128

            
129
    {
130
1
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");
131

            
132
1
        cr.translate(100.0, 100.0);
133

            
134
1
        cr.rectangle(10.0, 10.0, 60.0, 80.0);
135
1
        cr.set_source_rgba(0.0, 0.0, 1.0, 1.0);
136
1
        cr.fill_preserve().unwrap();
137

            
138
1
        cr.set_line_width(20.0);
139
1
        cr.set_source_rgba(0.0, 0.0, 0.0, 1.0);
140
1
        cr.stroke().unwrap();
141
1
    }
142

            
143
1
    Reference::from_surface(reference_surf)
144
        .compare(&output_surf)
145
1
        .evaluate(&output_surf, "untransformed_element");
146
2
}
147

            
148
#[test]
149
2
fn set_stylesheet() {
150
    // This has a rectangle which we style from a user-supplied stylesheet.
151
1
    let mut svg = load_svg(
152
        br##"<?xml version="1.0" encoding="UTF-8"?>
153
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
154
  <rect id="foo" x="10" y="20" width="30" height="40" fill="black"/>
155
</svg>
156
"##,
157
    )
158
    .unwrap();
159

            
160
1
    svg.set_stylesheet("rect { fill: #00ff00; }")
161
        .expect("should be a valid stylesheet");
162

            
163
1
    let renderer = CairoRenderer::new(&svg);
164

            
165
1
    let output = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();
166

            
167
    let res = {
168
1
        let cr = cairo::Context::new(&output).expect("Failed to create cairo context");
169
1
        let viewport = cairo::Rectangle::new(0.0, 0.0, 100.0, 100.0);
170

            
171
1
        renderer.render_document(&cr, &viewport)
172
1
    };
173

            
174
1
    let output_surf = res
175
2
        .map(|_| SharedImageSurface::wrap(output, SurfaceType::SRgb).unwrap())
176
        .unwrap();
177

            
178
1
    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();
179

            
180
    {
181
1
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");
182

            
183
1
        cr.rectangle(10.0, 20.0, 30.0, 40.0);
184
1
        cr.set_source_rgba(0.0, 1.0, 0.0, 1.0);
185
1
        cr.fill().unwrap();
186
1
    }
187

            
188
1
    Reference::from_surface(reference_surf)
189
        .compare(&output_surf)
190
1
        .evaluate(&output_surf, "set_stylesheet");
191
2
}
192

            
193
// https://gitlab.gnome.org/GNOME/librsvg/-/issues/799
194
#[test]
195
2
fn text_doesnt_leave_points_in_current_path() {
196
1
    let svg = load_svg(
197
        br##"<?xml version="1.0" encoding="UTF-8"?>
198
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
199
  <text>Hello world!</text>
200
</svg>
201
"##,
202
    )
203
    .unwrap();
204

            
205
1
    let renderer = CairoRenderer::new(&svg);
206

            
207
1
    let output = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();
208
1
    let cr = cairo::Context::new(&output).unwrap();
209

            
210
1
    assert!(!cr.has_current_point().unwrap());
211

            
212
1
    let viewport = cairo::Rectangle::new(0.0, 0.0, 100.0, 100.0);
213

            
214
1
    renderer.render_document(&cr, &viewport).unwrap();
215

            
216
1
    assert!(!cr.has_current_point().unwrap());
217
2
}
218

            
219
#[test]
220
2
fn cancellation_works() {
221
1
    let svg = load_svg(
222
        br##"<?xml version="1.0" encoding="UTF-8"?>
223
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
224
  <rect x="0" y="0" width="100%" height="100%" fill="blue"/>
225
</svg>
226
"##,
227
    )
228
    .unwrap();
229

            
230
    // To test cancellation, we'll start out by creating a cancellable and a renderer, and
231
    // immediately cancelling the operation.  Then we'll start rendering.  In theory this
232
    // will cause nothing to be rendered.
233

            
234
1
    let cancellable = gio::Cancellable::new();
235

            
236
1
    let renderer = CairoRenderer::new(&svg).with_cancellable(&cancellable);
237
1
    cancellable.cancel();
238

            
239
1
    let output = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();
240

            
241
    {
242
1
        let cr = cairo::Context::new(&output).unwrap();
243
1
        let viewport = cairo::Rectangle::new(0.0, 0.0, 100.0, 100.0);
244

            
245
        // Test that cancellation happens...
246
1
        assert!(matches!(
247
1
            renderer.render_document(&cr, &viewport),
248
            Err(RenderingError::Cancelled)
249
        ));
250
1
    }
251

            
252
1
    let output_surf = SharedImageSurface::wrap(output, SurfaceType::SRgb).unwrap();
253

            
254
    // ... and test that we got an empty surface, since hopefully cancellation occurred
255
    // before actually rendering anything.
256
1
    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();
257

            
258
1
    Reference::from_surface(reference_surf)
259
        .compare(&output_surf)
260
1
        .evaluate(&output_surf, "cancellation_works");
261
2
}