1
pub mod compare_surfaces;
2
pub mod reference_utils;
3

            
4
use cairo;
5
use gio;
6
use glib;
7
use std::env;
8
use std::sync::Once;
9

            
10
use crate::{
11
    CairoRenderer, Loader, LoadingError, RenderingError, SvgHandle,
12
    surface_utils::shared_surface::{SharedImageSurface, SurfaceType},
13
};
14

            
15
1820
pub fn load_svg(input: &'static [u8]) -> Result<SvgHandle, LoadingError> {
16
1820
    let bytes = glib::Bytes::from_static(input);
17
1820
    let stream = gio::MemoryInputStream::from_bytes(&bytes);
18

            
19
1820
    Loader::new().read_stream(&stream, None::<&gio::File>, None::<&gio::Cancellable>)
20
1820
}
21

            
22
#[derive(Copy, Clone)]
23
pub struct SurfaceSize(pub i32, pub i32);
24

            
25
2450
pub fn render_document<F: FnOnce(&cairo::Context)>(
26
2450
    svg: &SvgHandle,
27
2450
    surface_size: SurfaceSize,
28
2450
    cr_transform: F,
29
2450
    viewport: cairo::Rectangle,
30
2450
) -> Result<SharedImageSurface, RenderingError> {
31
2450
    let renderer = CairoRenderer::new(svg);
32

            
33
2450
    let SurfaceSize(width, height) = surface_size;
34

            
35
2450
    let output = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height).unwrap();
36

            
37
2450
    let res = {
38
2450
        let cr = cairo::Context::new(&output).expect("Failed to create a cairo context");
39
2450
        cr_transform(&cr);
40
2450
        Ok(renderer.render_document(&cr, &viewport)?)
41
    };
42

            
43
2450
    res.and_then(|_| Ok(SharedImageSurface::wrap(output, SurfaceType::SRgb)?))
44
2450
}
45

            
46
#[cfg(all(
47
    all(not(target_os = "macos"), not(target_os = "windows")),
48
    system_deps_have_fontconfig,
49
    system_deps_have_pangoft2
50
))]
51
mod pango_ft2 {
52
    use super::*;
53
    use glib::prelude::*;
54
    use glib::translate::*;
55
    use libc;
56
    use pangocairo::FontMap;
57
    use std::ffi::CString;
58
    use std::path::PathBuf;
59

            
60
    unsafe extern "C" {
61
        // pango_fc_font_map_set_config (PangoFcFontMap *fcfontmap,
62
        //                               FcConfig       *fcconfig);
63
        // This is not bound in gtk-rs, and PangoFcFontMap is not even exposed, so we'll bind it by hand.
64
        fn pango_fc_font_map_set_config(
65
            font_map: *mut libc::c_void,
66
            config: *mut fontconfig_sys::FcConfig,
67
        );
68
    }
69

            
70
15800
    pub unsafe fn load_test_fonts() {
71
15800
        let tests_resources_path: PathBuf = [
72
15800
            env::var("CARGO_MANIFEST_DIR")
73
15800
                .expect("Manifest directory unknown")
74
15800
                .as_str(),
75
15800
            "tests",
76
15800
            "resources",
77
15800
        ]
78
15800
        .iter()
79
15800
        .collect();
80

            
81
        unsafe {
82
15800
            let config = fontconfig_sys::FcConfigCreate();
83
15800
            if fontconfig_sys::FcConfigSetCurrent(config) == 0 {
84
                panic!("Could not set a fontconfig configuration");
85
15800
            }
86

            
87
15800
            let fonts_dot_conf_path = tests_resources_path.clone().join("fonts.conf");
88
15800
            let fonts_dot_conf_cstring =
89
15800
                CString::new(fonts_dot_conf_path.to_str().unwrap()).unwrap();
90
15800
            if fontconfig_sys::FcConfigParseAndLoad(
91
15800
                config,
92
15800
                fonts_dot_conf_cstring.as_ptr().cast(),
93
15800
                1,
94
15800
            ) == 0
95
            {
96
                panic!("Could not parse fontconfig configuration from tests/resources/fonts.conf");
97
15800
            }
98

            
99
15800
            let tests_resources_cstring =
100
15800
                CString::new(tests_resources_path.to_str().unwrap()).unwrap();
101
15800
            if fontconfig_sys::FcConfigAppFontAddDir(
102
15800
                config,
103
15800
                tests_resources_cstring.as_ptr().cast(),
104
15800
            ) == 0
105
            {
106
                panic!("Could not load fonts from directory tests/resources");
107
15800
            }
108

            
109
15800
            let font_map = FontMap::for_font_type(cairo::FontType::FontTypeFt).unwrap();
110
15800
            let raw_font_map: *mut pango::ffi::PangoFontMap = font_map.to_glib_none().0;
111

            
112
15800
            pango_fc_font_map_set_config(raw_font_map as *mut _, config);
113
15800
            fontconfig_sys::FcConfigDestroy(config);
114

            
115
15800
            FontMap::set_default(Some(&font_map.downcast::<pangocairo::FontMap>().unwrap()));
116
        }
117
15800
    }
118
}
119

            
120
#[cfg(all(
121
    all(not(target_os = "macos"), not(target_os = "windows")),
122
    system_deps_have_fontconfig,
123
    system_deps_have_pangoft2
124
))]
125
15800
pub fn setup_font_map() {
126
15800
    unsafe {
127
15800
        self::pango_ft2::load_test_fonts();
128
15800
    }
129
15800
}
130

            
131
#[cfg(any(
132
    any(target_os = "macos", target_os = "windows"),
133
    not(system_deps_have_fontconfig),
134
    not(system_deps_have_pangoft2)
135
))]
136
pub fn setup_font_map() {}
137

            
138
14580
pub fn setup_language() {
139
    static ONCE: Once = Once::new();
140

            
141
14580
    ONCE.call_once(|| {
142
        // For systemLanguage attribute tests.
143
        // The trailing ":" is intentional to test gitlab#425.
144
40
        unsafe {
145
40
            env::set_var("LANGUAGE", "de:en_US:en:");
146
40
            env::set_var("LC_ALL", "de:en_US:en:");
147
40
        }
148
40
    });
149
14580
}