summaryrefslogtreecommitdiff
path: root/librsvg
diff options
context:
space:
mode:
authorFederico Mena Quintero <federico@gnome.org>2020-10-29 18:13:33 -0600
committerFederico Mena Quintero <federico@gnome.org>2020-10-30 17:37:45 -0600
commit47b8889ca57d94f568d83eaf126cd2e402d962c1 (patch)
tree4c9a4ceb0f79123946fd26bc9b013aacc217148f /librsvg
parent8abf768a90556c83b01e25cdedf7b3126e47768c (diff)
downloadlibrsvg-47b8889ca57d94f568d83eaf126cd2e402d962c1.tar.gz
Move the c_api sources to src/c_api
Diffstat (limited to 'librsvg')
-rw-r--r--librsvg/Cargo.toml41
-rw-r--r--librsvg/build.rs63
-rw-r--r--librsvg/c_api.rs2319
-rw-r--r--librsvg/color_utils.rs179
-rw-r--r--librsvg/dpi.rs78
-rw-r--r--librsvg/messages.rs119
-rw-r--r--librsvg/pixbuf_utils.rs365
-rw-r--r--librsvg/sizing.rs76
8 files changed, 0 insertions, 3240 deletions
diff --git a/librsvg/Cargo.toml b/librsvg/Cargo.toml
deleted file mode 100644
index 6e8c94f7..00000000
--- a/librsvg/Cargo.toml
+++ /dev/null
@@ -1,41 +0,0 @@
-[package]
-name = "librsvg_c_api"
-version = "0.0.1"
-authors = ["Federico Mena Quintero <federico@gnome.org>"]
-workspace = "../"
-build = "build.rs"
-edition = "2018"
-
-[lib]
-name = "rsvg_c_api"
-path = "lib.rs"
-crate-type = [ "staticlib", "rlib" ]
-
-[dependencies]
-bitflags = "1.0"
-cairo-rs = { version="0.8.0", features=["v1_16"] }
-cairo-sys-rs = "0.9.0"
-cast = "0.2.3"
-float-cmp = "0.8.0"
-gdk-pixbuf = "0.8.0"
-gdk-pixbuf-sys = "0.9.0"
-glib = "0.9.0"
-glib-sys = { version="0.9.1", features=["v2_50"] }
-gio = { version="0.8.1", features=["v2_50"] } # per configure.ac
-gio-sys = "0.9.1"
-gobject-sys = "0.9.0"
-libc = "0.2"
-rgb = { version="0.8", features=["argb"] }
-librsvg = { path = "../librsvg_crate" }
-rsvg_internals = { path = "../rsvg_internals" }
-url = "2"
-
-[dev-dependencies]
-criterion = "0.3"
-
-[build-dependencies]
-regex = "1.3.9"
-
-[[bench]]
-name = "pixbuf_from_surface"
-harness = false
diff --git a/librsvg/build.rs b/librsvg/build.rs
deleted file mode 100644
index 36e595d0..00000000
--- a/librsvg/build.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-use regex::Regex;
-use std::env;
-use std::fs::File;
-use std::io::prelude::*;
-use std::io::BufReader;
-use std::path::Path;
-
-fn main() {
- let mut major = None;
- let mut minor = None;
- let mut micro = None;
-
- {
- let file = File::open("../configure.ac")
- .expect("builds must take place within the librsvg source tree");
-
- let major_regex = Regex::new(r#"^m4_define\(\[rsvg_major_version\],\[(\d+)\]\)"#).unwrap();
- let minor_regex = Regex::new(r#"^m4_define\(\[rsvg_minor_version\],\[(\d+)\]\)"#).unwrap();
- let micro_regex = Regex::new(r#"^m4_define\(\[rsvg_micro_version\],\[(\d+)\]\)"#).unwrap();
-
- for line in BufReader::new(file).lines() {
- if let Ok(line) = line {
- if let Some(nums) = major_regex.captures(&line) {
- major = Some(String::from(
- nums.get(1).expect("major_regex matched once").as_str(),
- ));
- } else if let Some(nums) = minor_regex.captures(&line) {
- minor = Some(String::from(
- nums.get(1).expect("minor_regex matched once").as_str(),
- ));
- } else if let Some(nums) = micro_regex.captures(&line) {
- micro = Some(String::from(
- nums.get(1).expect("micro_regex matched once").as_str(),
- ));
- }
- }
- }
- }
-
- let output = Path::new(&env::var("OUT_DIR").unwrap()).join("version.rs");
- let mut file = File::create(output).expect("open version.rs for writing");
- file.write_all(
- format!(
- r#"
-use std::os::raw::c_uint;
-
-#[no_mangle]
-pub static rsvg_major_version: c_uint = {};
-
-#[no_mangle]
-pub static rsvg_minor_version: c_uint = {};
-
-#[no_mangle]
-pub static rsvg_micro_version: c_uint = {};
-"#,
- major.expect("major version is set"),
- minor.expect("minor version is set"),
- micro.expect("micro version is set")
- )
- .as_bytes(),
- )
- .expect("write version.rs");
-}
diff --git a/librsvg/c_api.rs b/librsvg/c_api.rs
deleted file mode 100644
index 563508f4..00000000
--- a/librsvg/c_api.rs
+++ /dev/null
@@ -1,2319 +0,0 @@
-//! Rust implementation of the C API for librsvg.
-//!
-//! The C API of librsvg revolves around an `RsvgHandle` GObject class, which is
-//! implemented as follows:
-//!
-//! * [`RsvgHandle`] and [`RsvgHandleClass`] are derivatives of `GObject` and
-//! `GObjectClass`. These are coded explicitly, instead of using
-//! `glib::subclass::simple::InstanceStruct<T>` and
-//! `glib::subclass::simple::ClassStruct<T>`, as the structs need need to be kept
-//! ABI-compatible with the traditional C API/ABI.
-//!
-//! * The actual data for a handle (e.g. the `RsvgHandle`'s private data, in GObject
-//! parlance) is in [`CHandle`].
-//!
-//! * Public C ABI functions are the `#[no_mangle]` functions with an `rsvg_` prefix.
-//!
-//! The C API is implemented in terms of the Rust API in `librsvg_crate`. In effect,
-//! `RsvgHandle` is a rather convoluted builder or adapter pattern that translates all the
-//! historical idiosyncrasies of the C API into the simple Rust API.
-//!
-//! [`RsvgHandle`]: struct.RsvgHandle.html
-//! [`RsvgHandleClass`]: struct.RsvgHandleClass.html
-//! [`CHandle`]: struct.CHandle.html
-
-use std::cell::{Cell, Ref, RefCell, RefMut};
-use std::ffi::{CStr, CString};
-use std::ops;
-use std::path::PathBuf;
-use std::ptr;
-use std::slice;
-use std::str;
-use std::sync::Once;
-use std::{f64, i32};
-
-use bitflags::bitflags;
-use gdk_pixbuf::Pixbuf;
-use gio::prelude::*;
-use glib::error::ErrorDomain;
-use url::Url;
-
-use glib::object::ObjectClass;
-use glib::subclass;
-use glib::subclass::object::ObjectClassSubclassExt;
-use glib::subclass::prelude::*;
-use glib::translate::*;
-use glib::value::{FromValue, FromValueOptional, SetValue};
-use glib::{
- glib_object_impl, glib_object_subclass, Bytes, Cast, ParamFlags, ParamSpec, StaticType,
- ToValue, Type, Value,
-};
-
-use glib::types::instance_of;
-
-use gobject_sys::{GEnumValue, GFlagsValue};
-
-use librsvg::{
- CairoRenderer, DefsLookupErrorKind, IntrinsicDimensions, Loader, LoadingError, RenderingError,
- SvgHandle,
-};
-
-use rsvg_internals::{
- rsvg_log,
- surface_utils::shared_surface::{SharedImageSurface, SurfaceType},
- RsvgLength,
-};
-
-use crate::dpi::Dpi;
-use crate::messages::{rsvg_g_critical, rsvg_g_warning};
-use crate::pixbuf_utils::{empty_pixbuf, pixbuf_from_surface};
-use crate::sizing::LegacySize;
-
-include!(concat!(env!("OUT_DIR"), "/version.rs"));
-
-mod handle_flags {
- // The following is entirely stolen from the auto-generated code
- // for GBindingFlags, from gtk-rs/glib/src/gobject/auto/flags.rs
-
- use super::*;
-
- // Keep these in sync with rsvg.h:RsvgHandleFlags
- #[rustfmt::skip]
- bitflags! {
- pub struct HandleFlags: u32 {
- const NONE = 0;
- const UNLIMITED = 1 << 0;
- const KEEP_IMAGE_DATA = 1 << 1;
- }
- }
-
- pub type RsvgHandleFlags = libc::c_uint;
-
- impl ToGlib for HandleFlags {
- type GlibType = RsvgHandleFlags;
-
- fn to_glib(&self) -> RsvgHandleFlags {
- self.bits()
- }
- }
-
- impl FromGlib<RsvgHandleFlags> for HandleFlags {
- fn from_glib(value: RsvgHandleFlags) -> HandleFlags {
- HandleFlags::from_bits_truncate(value)
- }
- }
-
- impl StaticType for HandleFlags {
- fn static_type() -> Type {
- unsafe { from_glib(rsvg_handle_flags_get_type()) }
- }
- }
-
- impl<'a> FromValueOptional<'a> for HandleFlags {
- unsafe fn from_value_optional(value: &Value) -> Option<Self> {
- Some(FromValue::from_value(value))
- }
- }
-
- impl<'a> FromValue<'a> for HandleFlags {
- unsafe fn from_value(value: &Value) -> Self {
- from_glib(gobject_sys::g_value_get_flags(value.to_glib_none().0))
- }
- }
-
- impl SetValue for HandleFlags {
- unsafe fn set_value(value: &mut Value, this: &Self) {
- gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, this.to_glib())
- }
- }
-}
-
-#[derive(Default, Copy, Clone)]
-struct LoadFlags {
- unlimited_size: bool,
- keep_image_data: bool,
-}
-
-use self::handle_flags::*;
-
-impl From<HandleFlags> for LoadFlags {
- fn from(hflags: HandleFlags) -> LoadFlags {
- LoadFlags {
- unlimited_size: hflags.contains(HandleFlags::UNLIMITED),
- keep_image_data: hflags.contains(HandleFlags::KEEP_IMAGE_DATA),
- }
- }
-}
-
-impl From<LoadFlags> for HandleFlags {
- fn from(lflags: LoadFlags) -> HandleFlags {
- let mut hflags = HandleFlags::empty();
-
- if lflags.unlimited_size {
- hflags.insert(HandleFlags::UNLIMITED);
- }
-
- if lflags.keep_image_data {
- hflags.insert(HandleFlags::KEEP_IMAGE_DATA);
- }
-
- hflags
- }
-}
-
-/// GObject class struct for RsvgHandle.
-///
-/// This is not done through `glib::subclass::simple::ClassStruct<T>` because we need
-/// to include the `_abi_padding` field for ABI compatibility with the C headers, and
-/// `simple::ClassStruct` does not allow that.
-#[repr(C)]
-pub struct RsvgHandleClass {
- // Keep this in sync with rsvg.h:RsvgHandleClass
- parent: gobject_sys::GObjectClass,
-
- _abi_padding: [glib_sys::gpointer; 15],
-}
-
-/// GObject instance struct for RsvgHandle.
-///
-/// This is not done through `glib::subclass::simple::InstanceStruct<T>` because we need
-/// to include the `_abi_padding` field for ABI compatibility with the C headers, and
-/// `simple::InstanceStruct` does not allow that.
-#[repr(C)]
-pub struct RsvgHandle {
- // Keep this in sync with rsvg.h:RsvgHandle
- parent: gobject_sys::GObject,
-
- _abi_padding: [glib_sys::gpointer; 16],
-}
-
-#[allow(clippy::large_enum_variant)]
-enum LoadState {
- // Just created the CHandle
- Start,
-
- // Being loaded using the legacy write()/close() API
- Loading { buffer: Vec<u8> },
-
- ClosedOk { handle: SvgHandle },
-
- ClosedError,
-}
-
-impl LoadState {
- fn set_from_loading_result(
- &mut self,
- result: Result<SvgHandle, LoadingError>,
- ) -> Result<(), LoadingError> {
- match result {
- Ok(handle) => {
- *self = LoadState::ClosedOk { handle };
- Ok(())
- }
-
- Err(e) => {
- *self = LoadState::ClosedError;
- Err(e)
- }
- }
- }
-}
-
-/// Holds the base URL for loading a handle, and the C-accessible version of it
-///
-/// There is a public API to query the base URL, and we need to
-/// produce a CString with it. However, that API returns a
-/// *const char, so we need to maintain a long-lived CString along with the
-/// internal Url.
-#[derive(Default)]
-struct BaseUrl {
- inner: Option<BaseUrlInner>,
-}
-
-struct BaseUrlInner {
- url: Url,
- cstring: CString,
-}
-
-impl BaseUrl {
- fn set(&mut self, url: Url) {
- let cstring = CString::new(url.as_str()).unwrap();
-
- self.inner = Some(BaseUrlInner { url, cstring });
- }
-
- fn get(&self) -> Option<&Url> {
- self.inner.as_ref().map(|b| &b.url)
- }
-
- fn get_gfile(&self) -> Option<gio::File> {
- self.get().map(|url| gio::File::new_for_uri(url.as_str()))
- }
-
- fn get_ptr(&self) -> *const libc::c_char {
- self.inner
- .as_ref()
- .map(|b| b.cstring.as_ptr())
- .unwrap_or_else(ptr::null)
- }
-}
-
-#[derive(Default, Clone, Copy, Debug, PartialEq)]
-#[repr(C)]
-pub struct RsvgRectangle {
- pub x: f64,
- pub y: f64,
- pub width: f64,
- pub height: f64,
-}
-
-impl From<cairo::Rectangle> for RsvgRectangle {
- fn from(r: cairo::Rectangle) -> RsvgRectangle {
- RsvgRectangle {
- x: r.x,
- y: r.y,
- width: r.width,
- height: r.height,
- }
- }
-}
-
-impl From<RsvgRectangle> for cairo::Rectangle {
- fn from(r: RsvgRectangle) -> cairo::Rectangle {
- cairo::Rectangle {
- x: r.x,
- y: r.y,
- width: r.width,
- height: r.height,
- }
- }
-}
-
-/// Contains all the interior mutability for a RsvgHandle to be called
-/// from the C API.
-pub struct CHandle {
- inner: RefCell<CHandleInner>,
- load_state: RefCell<LoadState>,
-}
-
-struct CHandleInner {
- dpi: Dpi,
- load_flags: LoadFlags,
- base_url: BaseUrl,
- size_callback: SizeCallback,
- is_testing: bool,
-}
-
-unsafe impl ClassStruct for RsvgHandleClass {
- type Type = CHandle;
-}
-
-unsafe impl InstanceStruct for RsvgHandle {
- type Type = CHandle;
-}
-
-impl ops::Deref for RsvgHandleClass {
- type Target = ObjectClass;
-
- fn deref(&self) -> &Self::Target {
- unsafe { &*(self as *const _ as *const Self::Target) }
- }
-}
-
-impl ops::DerefMut for RsvgHandleClass {
- fn deref_mut(&mut self) -> &mut Self::Target {
- unsafe { &mut *(self as *mut _ as *mut Self::Target) }
- }
-}
-
-static PROPERTIES: [subclass::Property; 11] = [
- subclass::Property("flags", |name| {
- ParamSpec::flags(
- name,
- "Flags",
- "Loading flags",
- HandleFlags::static_type(),
- 0,
- ParamFlags::READWRITE | ParamFlags::CONSTRUCT_ONLY,
- )
- }),
- subclass::Property("dpi-x", |name| {
- ParamSpec::double(
- name,
- "Horizontal DPI",
- "Horizontal resolution in dots per inch",
- 0.0,
- f64::MAX,
- 0.0,
- ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
- )
- }),
- subclass::Property("dpi-y", |name| {
- ParamSpec::double(
- name,
- "Vertical DPI",
- "Vertical resolution in dots per inch",
- 0.0,
- f64::MAX,
- 0.0,
- ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
- )
- }),
- subclass::Property("base-uri", |name| {
- ParamSpec::string(
- name,
- "Base URI",
- "Base URI for resolving relative references",
- None,
- ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
- )
- }),
- subclass::Property("width", |name| {
- ParamSpec::int(
- name,
- "Image width",
- "Image width",
- 0,
- i32::MAX,
- 0,
- ParamFlags::READABLE,
- )
- }),
- subclass::Property("height", |name| {
- ParamSpec::int(
- name,
- "Image height",
- "Image height",
- 0,
- i32::MAX,
- 0,
- ParamFlags::READABLE,
- )
- }),
- subclass::Property("em", |name| {
- ParamSpec::double(name, "em", "em", 0.0, f64::MAX, 0.0, ParamFlags::READABLE)
- }),
- subclass::Property("ex", |name| {
- ParamSpec::double(name, "ex", "ex", 0.0, f64::MAX, 0.0, ParamFlags::READABLE)
- }),
- subclass::Property("title", |name| {
- ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
- }),
- subclass::Property("desc", |name| {
- ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
- }),
- subclass::Property("metadata", |name| {
- ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
- }),
-];
-
-impl ObjectSubclass for CHandle {
- const NAME: &'static str = "RsvgHandle";
-
- type ParentType = glib::Object;
-
- // We don't use subclass:simple::InstanceStruct and ClassStruct
- // because we need to maintain the respective _abi_padding of each
- // of RsvgHandleClass and RsvgHandle.
-
- type Instance = RsvgHandle;
- type Class = RsvgHandleClass;
-
- glib_object_subclass!();
-
- fn class_init(klass: &mut RsvgHandleClass) {
- klass.install_properties(&PROPERTIES);
- }
-
- fn new() -> Self {
- CHandle {
- inner: RefCell::new(CHandleInner {
- dpi: Dpi::default(),
- load_flags: LoadFlags::default(),
- base_url: BaseUrl::default(),
- size_callback: SizeCallback::default(),
- is_testing: false,
- }),
- load_state: RefCell::new(LoadState::Start),
- }
- }
-}
-
-impl StaticType for CHandle {
- fn static_type() -> Type {
- CHandle::get_type()
- }
-}
-
-impl ObjectImpl for CHandle {
- glib_object_impl!();
-
- fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("flags", ..) => {
- let v: HandleFlags = value.get_some().expect("flags value has incorrect type");
- self.set_flags(v);
- }
-
- subclass::Property("dpi-x", ..) => {
- let dpi_x: f64 = value.get_some().expect("dpi-x value has incorrect type");
- self.set_dpi_x(dpi_x);
- }
-
- subclass::Property("dpi-y", ..) => {
- let dpi_y: f64 = value.get_some().expect("dpi-y value has incorrect type");
- self.set_dpi_y(dpi_y);
- }
-
- subclass::Property("base-uri", ..) => {
- let v: Option<String> = value.get().expect("base-uri value has incorrect type");
-
- // rsvg_handle_set_base_uri() expects non-NULL URI strings,
- // but the "base-uri" property can be set to NULL due to a missing
- // construct-time property.
-
- if let Some(s) = v {
- self.set_base_url(&s);
- }
- }
-
- _ => unreachable!("invalid property id {}", id),
- }
- }
-
- #[rustfmt::skip]
- fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("flags", ..) => Ok(self.get_flags().to_value()),
-
- subclass::Property("dpi-x", ..) => Ok(self.get_dpi_x().to_value()),
- subclass::Property("dpi-y", ..) => Ok(self.get_dpi_y().to_value()),
-
- subclass::Property("base-uri", ..) => Ok(self.get_base_url().to_value()),
-
- subclass::Property("width", ..) =>
- Ok(self.get_dimensions_or_empty().width.to_value()),
-
- subclass::Property("height", ..) =>
- Ok(self.get_dimensions_or_empty().height.to_value()),
-
- subclass::Property("em", ..) =>
- Ok(self.get_dimensions_or_empty().em.to_value()),
-
- subclass::Property("ex", ..) =>
- Ok(self.get_dimensions_or_empty().ex.to_value()),
-
- // the following three are deprecated
- subclass::Property("title", ..) => Ok((None as Option<String>).to_value()),
- subclass::Property("desc", ..) => Ok((None as Option<String>).to_value()),
- subclass::Property("metadata", ..) => Ok((None as Option<String>).to_value()),
-
- _ => unreachable!("invalid property id={} for RsvgHandle", id),
- }
- }
-}
-
-// Keep in sync with tests/src/reference.rs
-pub(crate) fn checked_i32(x: f64) -> Result<i32, cairo::Status> {
- cast::i32(x).map_err(|_| cairo::Status::InvalidSize)
-}
-
-// Keep in sync with rsvg.h:RsvgPositionData
-#[repr(C)]
-pub struct RsvgPositionData {
- pub x: libc::c_int,
- pub y: libc::c_int,
-}
-
-// Keep in sync with rsvg.h:RsvgDimensionData
-#[repr(C)]
-pub struct RsvgDimensionData {
- pub width: libc::c_int,
- pub height: libc::c_int,
- pub em: f64,
- pub ex: f64,
-}
-
-impl RsvgDimensionData {
- // This is not #[derive(Default)] to make it clear that it
- // shouldn't be the default value for anything; it is actually a
- // special case we use to indicate an error to the public API.
- pub fn empty() -> RsvgDimensionData {
- RsvgDimensionData {
- width: 0,
- height: 0,
- em: 0.0,
- ex: 0.0,
- }
- }
-}
-
-// Keep in sync with rsvg.h:RsvgSizeFunc
-pub type RsvgSizeFunc = Option<
- unsafe extern "C" fn(
- inout_width: *mut libc::c_int,
- inout_height: *mut libc::c_int,
- user_data: glib_sys::gpointer,
- ),
->;
-
-struct SizeCallback {
- size_func: RsvgSizeFunc,
- user_data: glib_sys::gpointer,
- destroy_notify: glib_sys::GDestroyNotify,
- in_loop: Cell<bool>,
-}
-
-impl SizeCallback {
- fn new(
- size_func: RsvgSizeFunc,
- user_data: glib_sys::gpointer,
- destroy_notify: glib_sys::GDestroyNotify,
- ) -> Self {
- SizeCallback {
- size_func,
- user_data,
- destroy_notify,
- in_loop: Cell::new(false),
- }
- }
-
- fn call(&self, width: libc::c_int, height: libc::c_int) -> (libc::c_int, libc::c_int) {
- unsafe {
- let mut w = width;
- let mut h = height;
-
- if let Some(ref f) = self.size_func {
- f(&mut w, &mut h, self.user_data);
- };
-
- (w, h)
- }
- }
-
- fn start_loop(&self) {
- assert!(!self.in_loop.get());
- self.in_loop.set(true);
- }
-
- fn end_loop(&self) {
- assert!(self.in_loop.get());
- self.in_loop.set(false);
- }
-
- fn get_in_loop(&self) -> bool {
- self.in_loop.get()
- }
-}
-
-impl Default for SizeCallback {
- fn default() -> SizeCallback {
- SizeCallback {
- size_func: None,
- user_data: ptr::null_mut(),
- destroy_notify: None,
- in_loop: Cell::new(false),
- }
- }
-}
-
-impl Drop for SizeCallback {
- fn drop(&mut self) {
- unsafe {
- if let Some(ref f) = self.destroy_notify {
- f(self.user_data);
- };
- }
- }
-}
-
-trait CairoRectangleExt {
- fn from_size(width: f64, height: f64) -> Self;
-}
-
-impl CairoRectangleExt for cairo::Rectangle {
- fn from_size(width: f64, height: f64) -> Self {
- Self {
- x: 0.0,
- y: 0.0,
- width,
- height,
- }
- }
-}
-
-impl CHandle {
- fn set_base_url(&self, url: &str) {
- let state = self.load_state.borrow();
-
- match *state {
- LoadState::Start => (),
- _ => {
- rsvg_g_critical(
- "Please set the base file or URI before loading any data into RsvgHandle",
- );
- return;
- }
- }
-
- match Url::parse(&url) {
- Ok(u) => {
- rsvg_log!("setting base_uri to \"{}\"", u.as_str());
- let mut inner = self.inner.borrow_mut();
- inner.base_url.set(u);
- }
-
- Err(e) => {
- rsvg_log!(
- "not setting base_uri to \"{}\" since it is invalid: {}",
- url,
- e
- );
- }
- }
- }
-
- fn set_base_gfile(&self, file: &gio::File) {
- self.set_base_url(&file.get_uri());
- }
-
- fn get_base_url(&self) -> Option<String> {
- let inner = self.inner.borrow();
- inner.base_url.get().map(|url| url.as_str().to_string())
- }
-
- fn get_base_url_as_ptr(&self) -> *const libc::c_char {
- let inner = self.inner.borrow();
- inner.base_url.get_ptr()
- }
-
- fn set_dpi_x(&self, dpi_x: f64) {
- let mut inner = self.inner.borrow_mut();
- let dpi = inner.dpi;
- inner.dpi = Dpi::new(dpi_x, dpi.y());
- }
-
- fn set_dpi_y(&self, dpi_y: f64) {
- let mut inner = self.inner.borrow_mut();
- let dpi = inner.dpi;
- inner.dpi = Dpi::new(dpi.x(), dpi_y);
- }
-
- fn get_dpi_x(&self) -> f64 {
- let inner = self.inner.borrow();
- inner.dpi.x()
- }
-
- fn get_dpi_y(&self) -> f64 {
- let inner = self.inner.borrow();
- inner.dpi.y()
- }
-
- fn set_flags(&self, flags: HandleFlags) {
- let mut inner = self.inner.borrow_mut();
- inner.load_flags = LoadFlags::from(flags);
- }
-
- fn get_flags(&self) -> HandleFlags {
- let inner = self.inner.borrow();
- HandleFlags::from(inner.load_flags)
- }
-
- fn set_size_callback(
- &self,
- size_func: RsvgSizeFunc,
- user_data: glib_sys::gpointer,
- destroy_notify: glib_sys::GDestroyNotify,
- ) {
- let mut inner = self.inner.borrow_mut();
- inner.size_callback = SizeCallback::new(size_func, user_data, destroy_notify);
- }
-
- fn write(&self, buf: &[u8]) {
- let mut state = self.load_state.borrow_mut();
-
- match *state {
- LoadState::Start => {
- *state = LoadState::Loading {
- buffer: Vec::from(buf),
- }
- }
-
- LoadState::Loading { ref mut buffer } => {
- buffer.extend_from_slice(buf);
- }
-
- _ => {
- rsvg_g_critical("Handle must not be closed in order to write to it");
- }
- }
- }
-
- fn close(&self) -> Result<(), LoadingError> {
- let inner = self.inner.borrow();
- let mut state = self.load_state.borrow_mut();
-
- match *state {
- LoadState::Start => {
- *state = LoadState::ClosedError;
- Err(LoadingError::NoDataPassedToParser)
- }
-
- LoadState::Loading { ref buffer } => {
- let bytes = Bytes::from(&*buffer);
- let stream = gio::MemoryInputStream::new_from_bytes(&bytes);
-
- let base_file = inner.base_url.get_gfile();
- self.read_stream(state, &stream.upcast(), base_file.as_ref(), None)
- }
-
- // Closing is idempotent
- LoadState::ClosedOk { .. } => Ok(()),
- LoadState::ClosedError => Ok(()),
- }
- }
-
- fn read_stream_sync(
- &self,
- stream: &gio::InputStream,
- cancellable: Option<&gio::Cancellable>,
- ) -> Result<(), LoadingError> {
- let state = self.load_state.borrow_mut();
- let inner = self.inner.borrow();
-
- match *state {
- LoadState::Start => {
- let base_file = inner.base_url.get_gfile();
- self.read_stream(state, stream, base_file.as_ref(), cancellable)
- }
-
- LoadState::Loading { .. } | LoadState::ClosedOk { .. } | LoadState::ClosedError => {
- rsvg_g_critical(
- "handle must not be already loaded in order to call \
- rsvg_handle_read_stream_sync()",
- );
- Err(LoadingError::Unknown)
- }
- }
- }
-
- fn read_stream(
- &self,
- mut load_state: RefMut<LoadState>,
- stream: &gio::InputStream,
- base_file: Option<&gio::File>,
- cancellable: Option<&gio::Cancellable>,
- ) -> Result<(), LoadingError> {
- let loader = self.make_loader();
-
- load_state.set_from_loading_result(loader.read_stream(stream, base_file, cancellable))
- }
-
- fn get_handle_ref(&self) -> Result<Ref<SvgHandle>, RenderingError> {
- let state = self.load_state.borrow();
-
- match *state {
- LoadState::Start => {
- rsvg_g_critical("Handle has not been loaded");
- Err(RenderingError::HandleIsNotLoaded)
- }
-
- LoadState::Loading { .. } => {
- rsvg_g_critical("Handle is still loading; call rsvg_handle_close() first");
- Err(RenderingError::HandleIsNotLoaded)
- }
-
- LoadState::ClosedError => {
- rsvg_g_critical(
- "Handle could not read or parse the SVG; did you check for errors during the \
- loading stage?",
- );
- Err(RenderingError::HandleIsNotLoaded)
- }
-
- LoadState::ClosedOk { .. } => Ok(Ref::map(state, |s| match *s {
- LoadState::ClosedOk { ref handle } => handle,
- _ => unreachable!(),
- })),
- }
- }
-
- fn make_loader(&self) -> Loader {
- let inner = self.inner.borrow();
-
- let mut loader = Loader::new();
-
- if inner.load_flags.unlimited_size {
- loader = loader.with_unlimited_size();
- }
-
- if inner.load_flags.keep_image_data {
- loader = loader.keep_image_data();
- }
-
- loader
- }
-
- fn has_sub(&self, id: &str) -> Result<bool, RenderingError> {
- let handle = self.get_handle_ref()?;
- handle.has_element_with_id(id).map_err(warn_on_invalid_id)
- }
-
- fn get_dimensions_or_empty(&self) -> RsvgDimensionData {
- self.get_dimensions_sub(None)
- .unwrap_or_else(|_| RsvgDimensionData::empty())
- }
-
- fn get_dimensions_sub(&self, id: Option<&str>) -> Result<RsvgDimensionData, RenderingError> {
- let inner = self.inner.borrow();
-
- // This function is probably called from the cairo_render functions,
- // or is being erroneously called within the size_func.
- // To prevent an infinite loop we are saving the state, and
- // returning a meaningless size.
- if inner.size_callback.get_in_loop() {
- return Ok(RsvgDimensionData {
- width: 1,
- height: 1,
- em: 1.0,
- ex: 1.0,
- });
- }
-
- inner.size_callback.start_loop();
-
- let res = self
- .get_geometry_sub(id)
- .and_then(|(ink_r, _)| {
- // Keep these in sync with tests/src/reference.rs
- let width = checked_i32(ink_r.width.round())?;
- let height = checked_i32(ink_r.height.round())?;
-
- Ok((ink_r, width, height))
- })
- .map(|(ink_r, width, height)| {
- let (w, h) = inner.size_callback.call(width, height);
-
- RsvgDimensionData {
- width: w,
- height: h,
- em: ink_r.width,
- ex: ink_r.height,
- }
- });
-
- inner.size_callback.end_loop();
-
- res.map_err(warn_on_invalid_id)
- }
-
- fn get_position_sub(&self, id: Option<&str>) -> Result<RsvgPositionData, RenderingError> {
- let inner = self.inner.borrow();
-
- if id.is_none() {
- return Ok(RsvgPositionData { x: 0, y: 0 });
- }
-
- self.get_geometry_sub(id)
- .and_then(|(ink_r, _)| {
- let width = checked_i32(ink_r.width.round())?;
- let height = checked_i32(ink_r.height.round())?;
-
- Ok((ink_r, width, height))
- })
- .and_then(|(ink_r, width, height)| {
- inner.size_callback.call(width, height);
-
- Ok(RsvgPositionData {
- x: checked_i32(ink_r.x)?,
- y: checked_i32(ink_r.y)?,
- })
- })
- .map_err(warn_on_invalid_id)
- }
-
- fn make_renderer<'a>(&self, handle_ref: &'a Ref<SvgHandle>) -> CairoRenderer<'a> {
- let inner = self.inner.borrow();
-
- let mut renderer = CairoRenderer::new(&*handle_ref).with_dpi(inner.dpi.x(), inner.dpi.y());
-
- if inner.is_testing {
- renderer = renderer.test_mode();
- }
-
- renderer
- }
-
- fn get_geometry_sub(
- &self,
- id: Option<&str>,
- ) -> Result<(cairo::Rectangle, cairo::Rectangle), RenderingError> {
- let handle = self.get_handle_ref()?;
- let renderer = self.make_renderer(&handle);
-
- match id {
- Some(id) => renderer.geometry_for_layer(Some(id), &unit_rectangle()),
-
- None => renderer.legacy_document_size_in_pixels().map(|(w, h)| {
- let rect = cairo::Rectangle::from_size(w, h);
- (rect, rect)
- }),
- }
- }
-
- fn set_stylesheet(&self, css: &str) -> Result<(), LoadingError> {
- match *self.load_state.borrow_mut() {
- LoadState::ClosedOk { ref mut handle } => handle.set_stylesheet(css),
-
- _ => {
- rsvg_g_critical(
- "handle must already be loaded in order to call \
- rsvg_handle_set_stylesheet()",
- );
- Err(LoadingError::Unknown)
- }
- }
- }
-
- fn render_cairo_sub(
- &self,
- cr: &cairo::Context,
- id: Option<&str>,
- ) -> Result<(), RenderingError> {
- check_cairo_context(cr)?;
-
- let dimensions = self.get_dimensions_sub(None)?;
- if dimensions.width == 0 || dimensions.height == 0 {
- // nothing to render
- return Ok(());
- }
-
- let viewport = cairo::Rectangle {
- x: 0.0,
- y: 0.0,
- width: f64::from(dimensions.width),
- height: f64::from(dimensions.height),
- };
-
- self.render_layer(cr, id, &viewport)
- }
-
- fn get_pixbuf_sub(&self, id: Option<&str>) -> Result<Pixbuf, RenderingError> {
- let dimensions = self.get_dimensions_sub(None)?;
-
- if dimensions.width == 0 || dimensions.height == 0 {
- return empty_pixbuf();
- }
-
- let surface = cairo::ImageSurface::create(
- cairo::Format::ARgb32,
- dimensions.width,
- dimensions.height,
- )?;
-
- {
- let cr = cairo::Context::new(&surface);
- self.render_cairo_sub(&cr, id)?;
- }
-
- let surface = SharedImageSurface::wrap(surface, SurfaceType::SRgb)?;
-
- pixbuf_from_surface(&surface)
- }
-
- fn render_document(
- &self,
- cr: &cairo::Context,
- viewport: &cairo::Rectangle,
- ) -> Result<(), RenderingError> {
- check_cairo_context(cr)?;
-
- let handle = self.get_handle_ref()?;
-
- let renderer = self.make_renderer(&handle);
- renderer.render_document(cr, viewport)
- }
-
- fn get_geometry_for_layer(
- &self,
- id: Option<&str>,
- viewport: &cairo::Rectangle,
- ) -> Result<(RsvgRectangle, RsvgRectangle), RenderingError> {
- let handle = self.get_handle_ref()?;
- let renderer = self.make_renderer(&handle);
-
- renderer
- .geometry_for_layer(id, viewport)
- .map(|(i, l)| (RsvgRectangle::from(i), RsvgRectangle::from(l)))
- .map_err(warn_on_invalid_id)
- }
-
- fn render_layer(
- &self,
- cr: &cairo::Context,
- id: Option<&str>,
- viewport: &cairo::Rectangle,
- ) -> Result<(), RenderingError> {
- check_cairo_context(cr)?;
-
- let handle = self.get_handle_ref()?;
-
- let renderer = self.make_renderer(&handle);
-
- renderer
- .render_layer(cr, id, viewport)
- .map_err(warn_on_invalid_id)
- }
-
- fn get_geometry_for_element(
- &self,
- id: Option<&str>,
- ) -> Result<(RsvgRectangle, RsvgRectangle), RenderingError> {
- let handle = self.get_handle_ref()?;
-
- let renderer = self.make_renderer(&handle);
-
- renderer
- .geometry_for_element(id)
- .map(|(i, l)| (RsvgRectangle::from(i), RsvgRectangle::from(l)))
- .map_err(warn_on_invalid_id)
- }
-
- fn render_element(
- &self,
- cr: &cairo::Context,
- id: Option<&str>,
- element_viewport: &cairo::Rectangle,
- ) -> Result<(), RenderingError> {
- check_cairo_context(cr)?;
-
- let handle = self.get_handle_ref()?;
-
- let renderer = self.make_renderer(&handle);
-
- renderer
- .render_element(cr, id, element_viewport)
- .map_err(warn_on_invalid_id)
- }
-
- fn get_intrinsic_dimensions(&self) -> Result<IntrinsicDimensions, RenderingError> {
- let handle = self.get_handle_ref()?;
- let renderer = self.make_renderer(&handle);
- Ok(renderer.intrinsic_dimensions())
- }
-
- fn get_intrinsic_size_in_pixels(&self) -> Result<Option<(f64, f64)>, RenderingError> {
- let handle = self.get_handle_ref()?;
- let renderer = self.make_renderer(&handle);
- Ok(renderer.intrinsic_size_in_pixels())
- }
-
- fn set_testing(&self, is_testing: bool) {
- let mut inner = self.inner.borrow_mut();
- inner.is_testing = is_testing;
- }
-}
-
-pub(crate) fn unit_rectangle() -> cairo::Rectangle {
- cairo::Rectangle::from_size(1.0, 1.0)
-}
-
-fn is_rsvg_handle(obj: *const RsvgHandle) -> bool {
- unsafe { instance_of::<CHandle>(obj as *const _) }
-}
-
-fn is_input_stream(obj: *mut gio_sys::GInputStream) -> bool {
- unsafe { instance_of::<gio::InputStream>(obj as *const _) }
-}
-
-fn is_gfile(obj: *const gio_sys::GFile) -> bool {
- unsafe { instance_of::<gio::File>(obj as *const _) }
-}
-
-fn is_cancellable(obj: *mut gio_sys::GCancellable) -> bool {
- unsafe { instance_of::<gio::Cancellable>(obj as *const _) }
-}
-
-fn get_rust_handle<'a>(handle: *const RsvgHandle) -> &'a CHandle {
- let handle = unsafe { &*handle };
- handle.get_impl()
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_type() -> glib_sys::GType {
- CHandle::get_type().to_glib()
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_error_get_type() -> glib_sys::GType {
- static ONCE: Once = Once::new();
- static mut ETYPE: glib_sys::GType = gobject_sys::G_TYPE_INVALID;
-
- // We have to store the GEnumValue in a static variable but
- // that requires it to be Sync. It is not Sync by default
- // because it contains pointers, so we have define a custom
- // wrapper type here on which we can implement Sync.
- #[repr(transparent)]
- struct GEnumValueWrapper(GEnumValue);
- unsafe impl Sync for GEnumValueWrapper {}
-
- static VALUES: [GEnumValueWrapper; 2] = [
- GEnumValueWrapper(GEnumValue {
- value: RSVG_ERROR_FAILED,
- value_name: b"RSVG_ERROR_FAILED\0" as *const u8 as *const _,
- value_nick: b"failed\0" as *const u8 as *const _,
- }),
- GEnumValueWrapper(GEnumValue {
- value: 0,
- value_name: 0 as *const _,
- value_nick: 0 as *const _,
- }),
- ];
-
- ONCE.call_once(|| {
- ETYPE = gobject_sys::g_enum_register_static(
- b"RsvgError\0" as *const u8 as *const _,
- &VALUES as *const GEnumValueWrapper as *const GEnumValue,
- );
- });
-
- ETYPE
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_flags_get_type() -> glib_sys::GType {
- static ONCE: Once = Once::new();
- static mut FTYPE: glib_sys::GType = gobject_sys::G_TYPE_INVALID;
-
- // We have to store the GFlagsValue in a static variable but
- // that requires it to be Sync. It is not Sync by default
- // because it contains pointers, so we have define a custom
- // wrapper type here on which we can implement Sync.
- #[repr(transparent)]
- struct GFlagsValueWrapper(GFlagsValue);
- unsafe impl Sync for GFlagsValueWrapper {}
-
- static VALUES: [GFlagsValueWrapper; 4] = [
- GFlagsValueWrapper(GFlagsValue {
- value: 0, // handle_flags::HandleFlags::NONE.bits(),
- value_name: b"RSVG_HANDLE_FLAGS_NONE\0" as *const u8 as *const _,
- value_nick: b"flags-none\0" as *const u8 as *const _,
- }),
- GFlagsValueWrapper(GFlagsValue {
- value: 1 << 0, // HandleFlags::UNLIMITED.to_glib(),
- value_name: b"RSVG_HANDLE_FLAG_UNLIMITED\0" as *const u8 as *const _,
- value_nick: b"flag-unlimited\0" as *const u8 as *const _,
- }),
- GFlagsValueWrapper(GFlagsValue {
- value: 1 << 1, // HandleFlags::KEEP_IMAGE_DATA.to_glib(),
- value_name: b"RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA\0" as *const u8 as *const _,
- value_nick: b"flag-keep-image-data\0" as *const u8 as *const _,
- }),
- GFlagsValueWrapper(GFlagsValue {
- value: 0,
- value_name: 0 as *const _,
- value_nick: 0 as *const _,
- }),
- ];
-
- ONCE.call_once(|| {
- FTYPE = gobject_sys::g_flags_register_static(
- b"RsvgHandleFlags\0" as *const u8 as *const _,
- &VALUES as *const GFlagsValueWrapper as *const GFlagsValue,
- );
- });
-
- FTYPE
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_set_base_uri(
- handle: *const RsvgHandle,
- uri: *const libc::c_char,
-) {
- rsvg_return_if_fail! {
- rsvg_handle_set_base_uri;
-
- is_rsvg_handle(handle),
- !uri.is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
-
- assert!(!uri.is_null());
- let uri: String = from_glib_none(uri);
-
- rhandle.set_base_url(&uri);
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_set_base_gfile(
- handle: *const RsvgHandle,
- raw_gfile: *mut gio_sys::GFile,
-) {
- rsvg_return_if_fail! {
- rsvg_handle_set_base_gfile;
-
- is_rsvg_handle(handle),
- is_gfile(raw_gfile),
- }
-
- let rhandle = get_rust_handle(handle);
-
- assert!(!raw_gfile.is_null());
-
- let file: gio::File = from_glib_none(raw_gfile);
-
- rhandle.set_base_gfile(&file);
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_base_uri(
- handle: *const RsvgHandle,
-) -> *const libc::c_char {
- rsvg_return_val_if_fail! {
- rsvg_handle_get_base_uri => ptr::null();
-
- is_rsvg_handle(handle),
- }
-
- let rhandle = get_rust_handle(handle);
-
- rhandle.get_base_url_as_ptr()
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_set_dpi(handle: *const RsvgHandle, dpi: libc::c_double) {
- rsvg_return_if_fail! {
- rsvg_handle_set_dpi;
-
- is_rsvg_handle(handle),
- }
-
- let rhandle = get_rust_handle(handle);
- rhandle.set_dpi_x(dpi);
- rhandle.set_dpi_y(dpi);
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_set_dpi_x_y(
- handle: *const RsvgHandle,
- dpi_x: libc::c_double,
- dpi_y: libc::c_double,
-) {
- rsvg_return_if_fail! {
- rsvg_handle_set_dpi_x_y;
-
- is_rsvg_handle(handle),
- }
-
- let rhandle = get_rust_handle(handle);
- rhandle.set_dpi_x(dpi_x);
- rhandle.set_dpi_y(dpi_y);
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_set_size_callback(
- handle: *const RsvgHandle,
- size_func: RsvgSizeFunc,
- user_data: glib_sys::gpointer,
- destroy_notify: glib_sys::GDestroyNotify,
-) {
- rsvg_return_if_fail! {
- rsvg_handle_set_size_callback;
-
- is_rsvg_handle(handle),
- }
-
- let rhandle = get_rust_handle(handle);
-
- rhandle.set_size_callback(size_func, user_data, destroy_notify);
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_internal_set_testing(
- handle: *const RsvgHandle,
- testing: glib_sys::gboolean,
-) {
- rsvg_return_if_fail! {
- rsvg_handle_internal_set_testing;
-
- is_rsvg_handle(handle),
- }
-
- let rhandle = get_rust_handle(handle);
-
- rhandle.set_testing(from_glib(testing));
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_read_stream_sync(
- handle: *const RsvgHandle,
- stream: *mut gio_sys::GInputStream,
- cancellable: *mut gio_sys::GCancellable,
- error: *mut *mut glib_sys::GError,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_read_stream_sync => false.to_glib();
-
- is_rsvg_handle(handle),
- is_input_stream(stream),
- cancellable.is_null() || is_cancellable(cancellable),
- error.is_null() || (*error).is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
-
- let stream = gio::InputStream::from_glib_none(stream);
- let cancellable: Option<gio::Cancellable> = from_glib_none(cancellable);
-
- match rhandle.read_stream_sync(&stream, cancellable.as_ref()) {
- Ok(()) => true.to_glib(),
-
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- false.to_glib()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_write(
- handle: *const RsvgHandle,
- buf: *const u8,
- count: usize,
- error: *mut *mut glib_sys::GError,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_write => false.to_glib();
-
- is_rsvg_handle(handle),
- error.is_null() || (*error).is_null(),
- (!buf.is_null() && count != 0) || (count == 0),
- }
-
- let rhandle = get_rust_handle(handle);
- let buffer = slice::from_raw_parts(buf, count);
- rhandle.write(buffer);
-
- true.to_glib()
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_close(
- handle: *const RsvgHandle,
- error: *mut *mut glib_sys::GError,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_close => false.to_glib();
-
- is_rsvg_handle(handle),
- error.is_null() || (*error).is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
-
- match rhandle.close() {
- Ok(()) => true.to_glib(),
-
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- false.to_glib()
- }
- }
-}
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_has_sub(
- handle: *const RsvgHandle,
- id: *const libc::c_char,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_has_sub => false.to_glib();
-
- is_rsvg_handle(handle),
- }
-
- let rhandle = get_rust_handle(handle);
-
- if id.is_null() {
- return false.to_glib();
- }
-
- let id: String = from_glib_none(id);
- rhandle.has_sub(&id).unwrap_or(false).to_glib()
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_render_cairo(
- handle: *const RsvgHandle,
- cr: *mut cairo_sys::cairo_t,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_render_cairo => false.to_glib();
-
- is_rsvg_handle(handle),
- !cr.is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
- let cr = from_glib_none(cr);
-
- match rhandle.render_cairo_sub(&cr, None) {
- Ok(()) => true.to_glib(),
-
- Err(e) => {
- rsvg_log!("could not render: {}", e);
- false.to_glib()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_render_cairo_sub(
- handle: *const RsvgHandle,
- cr: *mut cairo_sys::cairo_t,
- id: *const libc::c_char,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_render_cairo_sub => false.to_glib();
-
- is_rsvg_handle(handle),
- !cr.is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
- let cr = from_glib_none(cr);
- let id: Option<String> = from_glib_none(id);
-
- match rhandle.render_cairo_sub(&cr, id.as_deref()) {
- Ok(()) => true.to_glib(),
-
- Err(e) => {
- rsvg_log!("could not render: {}", e);
- false.to_glib()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_pixbuf(
- handle: *const RsvgHandle,
-) -> *mut gdk_pixbuf_sys::GdkPixbuf {
- rsvg_return_val_if_fail! {
- rsvg_handle_get_pixbuf => ptr::null_mut();
-
- is_rsvg_handle(handle),
- }
-
- let rhandle = get_rust_handle(handle);
-
- match rhandle.get_pixbuf_sub(None) {
- Ok(pixbuf) => pixbuf.to_glib_full(),
- Err(e) => {
- rsvg_log!("could not render: {}", e);
- ptr::null_mut()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_pixbuf_sub(
- handle: *const RsvgHandle,
- id: *const libc::c_char,
-) -> *mut gdk_pixbuf_sys::GdkPixbuf {
- rsvg_return_val_if_fail! {
- rsvg_handle_get_pixbuf_sub => ptr::null_mut();
-
- is_rsvg_handle(handle),
- }
-
- let rhandle = get_rust_handle(handle);
- let id: Option<String> = from_glib_none(id);
-
- match rhandle.get_pixbuf_sub(id.as_deref()) {
- Ok(pixbuf) => pixbuf.to_glib_full(),
- Err(e) => {
- rsvg_log!("could not render: {}", e);
- ptr::null_mut()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_dimensions(
- handle: *const RsvgHandle,
- dimension_data: *mut RsvgDimensionData,
-) {
- rsvg_handle_get_dimensions_sub(handle, dimension_data, ptr::null());
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_dimensions_sub(
- handle: *const RsvgHandle,
- dimension_data: *mut RsvgDimensionData,
- id: *const libc::c_char,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_get_dimensions_sub => false.to_glib();
-
- is_rsvg_handle(handle),
- !dimension_data.is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
-
- let id: Option<String> = from_glib_none(id);
-
- match rhandle.get_dimensions_sub(id.as_deref()) {
- Ok(dimensions) => {
- *dimension_data = dimensions;
- true.to_glib()
- }
-
- Err(e) => {
- rsvg_log!("could not get dimensions: {}", e);
- *dimension_data = RsvgDimensionData::empty();
- false.to_glib()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_position_sub(
- handle: *const RsvgHandle,
- position_data: *mut RsvgPositionData,
- id: *const libc::c_char,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_get_position_sub => false.to_glib();
-
- is_rsvg_handle(handle),
- !position_data.is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
-
- let id: Option<String> = from_glib_none(id);
-
- match rhandle.get_position_sub(id.as_deref()) {
- Ok(position) => {
- *position_data = position;
- true.to_glib()
- }
-
- Err(e) => {
- let p = &mut *position_data;
-
- p.x = 0;
- p.y = 0;
-
- rsvg_log!("could not get position: {}", e);
- false.to_glib()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_new() -> *const RsvgHandle {
- let obj: *mut gobject_sys::GObject = glib::Object::new(CHandle::get_type(), &[])
- .unwrap()
- .to_glib_full();
-
- obj as *mut _
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_new_with_flags(flags: RsvgHandleFlags) -> *const RsvgHandle {
- let obj: *mut gobject_sys::GObject =
- glib::Object::new(CHandle::get_type(), &[("flags", &flags)])
- .unwrap()
- .to_glib_full();
-
- obj as *mut _
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_new_from_file(
- filename: *const libc::c_char,
- error: *mut *mut glib_sys::GError,
-) -> *const RsvgHandle {
- rsvg_return_val_if_fail! {
- rsvg_handle_new_from_file => ptr::null();
-
- !filename.is_null(),
- error.is_null() || (*error).is_null(),
- }
-
- let file = match PathOrUrl::new(filename) {
- Ok(PathOrUrl::Path(path)) => gio::File::new_for_path(path),
-
- Ok(PathOrUrl::Url(url)) => gio::File::new_for_uri(url.as_str()),
-
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- return ptr::null_mut();
- }
- };
-
- rsvg_handle_new_from_gfile_sync(file.to_glib_none().0, 0, ptr::null_mut(), error)
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_new_from_gfile_sync(
- file: *mut gio_sys::GFile,
- flags: RsvgHandleFlags,
- cancellable: *mut gio_sys::GCancellable,
- error: *mut *mut glib_sys::GError,
-) -> *const RsvgHandle {
- rsvg_return_val_if_fail! {
- rsvg_handle_new_from_gfile_sync => ptr::null();
-
- is_gfile(file),
- cancellable.is_null() || is_cancellable(cancellable),
- error.is_null() || (*error).is_null(),
- }
-
- let raw_handle = rsvg_handle_new_with_flags(flags);
-
- let rhandle = get_rust_handle(raw_handle);
-
- let file = gio::File::from_glib_none(file);
- rhandle.set_base_gfile(&file);
-
- let cancellable: Option<gio::Cancellable> = from_glib_none(cancellable);
-
- let res = file
- .read(cancellable.as_ref())
- .map_err(LoadingError::from)
- .and_then(|stream| rhandle.read_stream_sync(&stream.upcast(), cancellable.as_ref()));
-
- match res {
- Ok(()) => raw_handle,
-
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- gobject_sys::g_object_unref(raw_handle as *mut _);
- ptr::null_mut()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_new_from_stream_sync(
- input_stream: *mut gio_sys::GInputStream,
- base_file: *mut gio_sys::GFile,
- flags: RsvgHandleFlags,
- cancellable: *mut gio_sys::GCancellable,
- error: *mut *mut glib_sys::GError,
-) -> *const RsvgHandle {
- rsvg_return_val_if_fail! {
- rsvg_handle_new_from_stream_sync => ptr::null();
-
- is_input_stream(input_stream),
- base_file.is_null() || is_gfile(base_file),
- cancellable.is_null() || is_cancellable(cancellable),
- error.is_null() || (*error).is_null(),
- }
-
- let raw_handle = rsvg_handle_new_with_flags(flags);
-
- let rhandle = get_rust_handle(raw_handle);
-
- let base_file: Option<gio::File> = from_glib_none(base_file);
- if let Some(base_file) = base_file {
- rhandle.set_base_gfile(&base_file);
- }
-
- let stream: gio::InputStream = from_glib_none(input_stream);
- let cancellable: Option<gio::Cancellable> = from_glib_none(cancellable);
-
- match rhandle.read_stream_sync(&stream, cancellable.as_ref()) {
- Ok(()) => raw_handle,
-
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- gobject_sys::g_object_unref(raw_handle as *mut _);
- ptr::null_mut()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_new_from_data(
- data: *const u8,
- data_len: usize,
- error: *mut *mut glib_sys::GError,
-) -> *const RsvgHandle {
- rsvg_return_val_if_fail! {
- rsvg_handle_new_from_data => ptr::null();
-
- (!data.is_null() && data_len != 0) || (data_len == 0),
- data_len <= std::isize::MAX as usize,
- error.is_null() || (*error).is_null(),
- }
-
- // We create the MemoryInputStream without the gtk-rs binding because of this:
- //
- // - The binding doesn't provide _new_from_data(). All of the binding's ways to
- // put data into a MemoryInputStream involve copying the data buffer.
- //
- // - We can't use glib::Bytes from the binding either, for the same reason.
- //
- // - For now, we are using the other C-visible constructor, so we need a raw pointer to the
- // stream, anyway.
-
- assert!(data_len <= std::isize::MAX as usize);
- let data_len = data_len as isize;
-
- let raw_stream = gio_sys::g_memory_input_stream_new_from_data(data as *mut u8, data_len, None);
-
- let ret = rsvg_handle_new_from_stream_sync(
- raw_stream as *mut _,
- ptr::null_mut(), // base_file
- 0, // flags
- ptr::null_mut(), // cancellable
- error,
- );
-
- gobject_sys::g_object_unref(raw_stream as *mut _);
- ret
-}
-
-unsafe fn set_out_param<T: Copy>(
- out_has_param: *mut glib_sys::gboolean,
- out_param: *mut T,
- value: &Option<T>,
-) {
- let has_value = if let Some(ref v) = *value {
- if !out_param.is_null() {
- *out_param = *v;
- }
-
- true
- } else {
- false
- };
-
- if !out_has_param.is_null() {
- *out_has_param = has_value.to_glib();
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_free(handle: *mut RsvgHandle) {
- gobject_sys::g_object_unref(handle as *mut _);
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_set_stylesheet(
- handle: *const RsvgHandle,
- css: *const u8,
- css_len: usize,
- error: *mut *mut glib_sys::GError,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_set_stylesheet => false.to_glib();
-
- is_rsvg_handle(handle),
- !css.is_null() || (css.is_null() && css_len == 0),
- error.is_null() || (*error).is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
-
- let css = match (css, css_len) {
- (p, 0) if p.is_null() => "",
- (_, _) => {
- let s = slice::from_raw_parts(css, css_len);
- match str::from_utf8(s) {
- Ok(s) => s,
- Err(e) => {
- set_gerror(error, 0, &format!("CSS is not valid UTF-8: {}", e));
- return false.to_glib();
- }
- }
- }
- };
-
- match rhandle.set_stylesheet(css) {
- Ok(()) => true.to_glib(),
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- false.to_glib()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_intrinsic_dimensions(
- handle: *const RsvgHandle,
- out_has_width: *mut glib_sys::gboolean,
- out_width: *mut RsvgLength,
- out_has_height: *mut glib_sys::gboolean,
- out_height: *mut RsvgLength,
- out_has_viewbox: *mut glib_sys::gboolean,
- out_viewbox: *mut RsvgRectangle,
-) {
- rsvg_return_if_fail! {
- rsvg_handle_get_intrinsic_dimensions;
-
- is_rsvg_handle(handle),
- }
-
- let rhandle = get_rust_handle(handle);
-
- let d = rhandle
- .get_intrinsic_dimensions()
- .unwrap_or_else(|_| panic!("API called out of order"));
-
- let w = d.width;
- let h = d.height;
- let r = d.vbox.map(RsvgRectangle::from);
-
- set_out_param(out_has_width, out_width, &w.map(Into::into));
- set_out_param(out_has_height, out_height, &h.map(Into::into));
- set_out_param(out_has_viewbox, out_viewbox, &r);
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_intrinsic_size_in_pixels(
- handle: *const RsvgHandle,
- out_width: *mut f64,
- out_height: *mut f64,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_get_intrinsic_size_in_pixels => false.to_glib();
-
- is_rsvg_handle(handle),
- }
-
- let rhandle = get_rust_handle(handle);
-
- let dim = rhandle
- .get_intrinsic_size_in_pixels()
- .unwrap_or_else(|_| panic!("API called out of order"));
-
- let (w, h) = dim.unwrap_or((0.0, 0.0));
-
- if !out_width.is_null() {
- *out_width = w;
- }
-
- if !out_height.is_null() {
- *out_height = h;
- }
-
- dim.is_some().to_glib()
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_render_document(
- handle: *const RsvgHandle,
- cr: *mut cairo_sys::cairo_t,
- viewport: *const RsvgRectangle,
- error: *mut *mut glib_sys::GError,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_render_document => false.to_glib();
-
- is_rsvg_handle(handle),
- !cr.is_null(),
- !viewport.is_null(),
- error.is_null() || (*error).is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
- let cr = from_glib_none(cr);
-
- match rhandle.render_document(&cr, &(*viewport).into()) {
- Ok(()) => true.to_glib(),
-
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- false.to_glib()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_geometry_for_layer(
- handle: *mut RsvgHandle,
- id: *const libc::c_char,
- viewport: *const RsvgRectangle,
- out_ink_rect: *mut RsvgRectangle,
- out_logical_rect: *mut RsvgRectangle,
- error: *mut *mut glib_sys::GError,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_get_geometry_for_layer => false.to_glib();
-
- is_rsvg_handle(handle),
- !viewport.is_null(),
- error.is_null() || (*error).is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
-
- let id: Option<String> = from_glib_none(id);
-
- match rhandle.get_geometry_for_layer(id.as_deref(), &(*viewport).into()) {
- Ok((ink_rect, logical_rect)) => {
- if !out_ink_rect.is_null() {
- *out_ink_rect = ink_rect;
- }
-
- if !out_logical_rect.is_null() {
- *out_logical_rect = logical_rect;
- }
-
- true.to_glib()
- }
-
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- false.to_glib()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_render_layer(
- handle: *const RsvgHandle,
- cr: *mut cairo_sys::cairo_t,
- id: *const libc::c_char,
- viewport: *const RsvgRectangle,
- error: *mut *mut glib_sys::GError,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_render_layer => false.to_glib();
-
- is_rsvg_handle(handle),
- !cr.is_null(),
- !viewport.is_null(),
- error.is_null() || (*error).is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
- let cr = from_glib_none(cr);
- let id: Option<String> = from_glib_none(id);
-
- match rhandle.render_layer(&cr, id.as_deref(), &(*viewport).into()) {
- Ok(()) => true.to_glib(),
-
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- false.to_glib()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_geometry_for_element(
- handle: *const RsvgHandle,
- id: *const libc::c_char,
- out_ink_rect: *mut RsvgRectangle,
- out_logical_rect: *mut RsvgRectangle,
- error: *mut *mut glib_sys::GError,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_get_geometry_for_element => false.to_glib();
-
- is_rsvg_handle(handle),
- error.is_null() || (*error).is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
-
- let id: Option<String> = from_glib_none(id);
-
- match rhandle.get_geometry_for_element(id.as_deref()) {
- Ok((ink_rect, logical_rect)) => {
- if !out_ink_rect.is_null() {
- *out_ink_rect = ink_rect;
- }
-
- if !out_logical_rect.is_null() {
- *out_logical_rect = logical_rect;
- }
-
- true.to_glib()
- }
-
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- false.to_glib()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_render_element(
- handle: *const RsvgHandle,
- cr: *mut cairo_sys::cairo_t,
- id: *const libc::c_char,
- element_viewport: *const RsvgRectangle,
- error: *mut *mut glib_sys::GError,
-) -> glib_sys::gboolean {
- rsvg_return_val_if_fail! {
- rsvg_handle_render_element => false.to_glib();
-
- is_rsvg_handle(handle),
- !cr.is_null(),
- !element_viewport.is_null(),
- error.is_null() || (*error).is_null(),
- }
-
- let rhandle = get_rust_handle(handle);
- let cr = from_glib_none(cr);
- let id: Option<String> = from_glib_none(id);
-
- match rhandle.render_element(&cr, id.as_deref(), &(*element_viewport).into()) {
- Ok(()) => true.to_glib(),
-
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- false.to_glib()
- }
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_desc(handle: *const RsvgHandle) -> *mut libc::c_char {
- rsvg_return_val_if_fail! {
- rsvg_handle_get_desc => ptr::null_mut();
-
- is_rsvg_handle(handle),
- }
-
- ptr::null_mut()
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_metadata(handle: *const RsvgHandle) -> *mut libc::c_char {
- rsvg_return_val_if_fail! {
- rsvg_handle_get_metadata => ptr::null_mut();
-
- is_rsvg_handle(handle),
- }
-
- ptr::null_mut()
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_handle_get_title(handle: *const RsvgHandle) -> *mut libc::c_char {
- rsvg_return_val_if_fail! {
- rsvg_handle_get_title => ptr::null_mut();
-
- is_rsvg_handle(handle),
- }
-
- ptr::null_mut()
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_init() {}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_term() {}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_cleanup() {}
-
-/// Detects whether a `*const libc::c_char` is a path or a URI
-///
-/// `rsvg_handle_new_from_file()` takes a `filename` argument, and advertises
-/// that it will detect either a file system path, or a proper URI. It will then use
-/// `gio::File::new_for_path()` or `gio::File::new_for_uri()` as appropriate.
-///
-/// This enum does the magic heuristics to figure this out.
-enum PathOrUrl {
- Path(PathBuf),
- Url(Url),
-}
-
-impl PathOrUrl {
- unsafe fn new(s: *const libc::c_char) -> Result<PathOrUrl, LoadingError> {
- let cstr = CStr::from_ptr(s);
-
- Ok(cstr
- .to_str()
- .map_err(|_| ())
- .and_then(|utf8| Url::parse(utf8).map_err(|_| ()))
- .and_then(|url| {
- if url.origin().is_tuple() || url.scheme() == "file" {
- Ok(PathOrUrl::Url(url))
- } else {
- Ok(PathOrUrl::Path(url.to_file_path()?))
- }
- })
- .unwrap_or_else(|_| PathOrUrl::Path(PathBuf::from_glib_none(s))))
- }
-}
-
-fn check_cairo_context(cr: &cairo::Context) -> Result<(), RenderingError> {
- let status = cr.status();
- if status == cairo::Status::Success {
- Ok(())
- } else {
- let msg = format!(
- "cannot render on a cairo_t with a failure status (status={:?})",
- status,
- );
-
- rsvg_g_warning(&msg);
- Err(RenderingError::Cairo(status))
- }
-}
-
-fn warn_on_invalid_id(e: RenderingError) -> RenderingError {
- if e == RenderingError::InvalidId(DefsLookupErrorKind::CannotLookupExternalReferences) {
- rsvg_g_warning("the public API is not allowed to look up external references");
- }
-
- e
-}
-
-pub(crate) fn set_gerror(err: *mut *mut glib_sys::GError, code: u32, msg: &str) {
- unsafe {
- // this is RSVG_ERROR_FAILED, the only error code available in RsvgError
- assert!(code == 0);
-
- // Log this, in case the calling program passes a NULL GError, so we can at least
- // diagnose things by asking for RSVG_LOG.
- //
- // See https://gitlab.gnome.org/GNOME/gtk/issues/2294 for an example of code that
- // passed a NULL GError and so we had no easy way to see what was wrong.
- rsvg_log!("{}", msg);
-
- glib_sys::g_set_error_literal(
- err,
- rsvg_error_quark(),
- code as libc::c_int,
- msg.to_glib_none().0,
- );
- }
-}
-
-/// Used as a generic error to translate to glib::Error
-///
-/// This type implements `glib::error::ErrorDomain`, so it can be used
-/// to obtain the error code while calling `glib::Error::new()`. Unfortunately
-/// the public librsvg API does not have detailed error codes yet, so we use
-/// this single value as the only possible error code to return.
-#[derive(Copy, Clone)]
-struct RsvgError;
-
-// Keep in sync with rsvg.h:RsvgError
-const RSVG_ERROR_FAILED: i32 = 0;
-
-impl ErrorDomain for RsvgError {
- fn domain() -> glib::Quark {
- glib::Quark::from_string("rsvg-error-quark")
- }
-
- fn code(self) -> i32 {
- RSVG_ERROR_FAILED
- }
-
- fn from(_code: i32) -> Option<Self> {
- // We don't have enough information from glib error codes
- Some(RsvgError)
- }
-}
-
-#[no_mangle]
-pub extern "C" fn rsvg_error_quark() -> glib_sys::GQuark {
- RsvgError::domain().to_glib()
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn path_or_url_unix() {
- unsafe {
- match PathOrUrl::new(b"/foo/bar\0" as *const u8 as *const _).unwrap() {
- PathOrUrl::Path(_) => (),
- _ => panic!("unix filename should be a PathOrUrl::Path"),
- }
-
- match PathOrUrl::new(b"foo/bar\0" as *const u8 as *const _).unwrap() {
- PathOrUrl::Path(_) => (),
- _ => panic!("unix filename should be a PathOrUrl::Path"),
- }
- }
- }
-
- #[test]
- fn path_or_url_windows() {
- unsafe {
- match PathOrUrl::new(b"c:/foo/bar\0" as *const u8 as *const _).unwrap() {
- PathOrUrl::Path(_) => (),
- _ => panic!("windows filename should be a PathOrUrl::Path"),
- }
-
- match PathOrUrl::new(b"C:/foo/bar\0" as *const u8 as *const _).unwrap() {
- PathOrUrl::Path(_) => (),
- _ => panic!("windows filename should be a PathOrUrl::Path"),
- }
-
- match PathOrUrl::new(b"c:\\foo\\bar\0" as *const u8 as *const _).unwrap() {
- PathOrUrl::Path(_) => (),
- _ => panic!("windows filename should be a PathOrUrl::Path"),
- }
-
- match PathOrUrl::new(b"C:\\foo\\bar\0" as *const u8 as *const _).unwrap() {
- PathOrUrl::Path(_) => (),
- _ => panic!("windows filename should be a PathOrUrl::Path"),
- }
- }
- }
-
- #[test]
- fn path_or_url_unix_url() {
- unsafe {
- match PathOrUrl::new(b"file:///foo/bar\0" as *const u8 as *const _).unwrap() {
- PathOrUrl::Url(_) => (),
- _ => panic!("file:// unix filename should be a PathOrUrl::Url"),
- }
- }
- }
-
- #[test]
- fn path_or_url_windows_url() {
- unsafe {
- match PathOrUrl::new(b"file://c:/foo/bar\0" as *const u8 as *const _).unwrap() {
- PathOrUrl::Url(_) => (),
- _ => panic!("file:// windows filename should be a PathOrUrl::Url"),
- }
-
- match PathOrUrl::new(b"file://C:/foo/bar\0" as *const u8 as *const _).unwrap() {
- PathOrUrl::Url(_) => (),
- _ => panic!("file:// windows filename should be a PathOrUrl::Url"),
- }
- }
- }
-
- #[test]
- fn base_url_works() {
- let mut u = BaseUrl::default();
-
- assert!(u.get().is_none());
- assert_eq!(u.get_ptr(), ptr::null());
-
- u.set(Url::parse("file:///example.txt").unwrap());
-
- assert_eq!(u.get().unwrap().as_str(), "file:///example.txt");
-
- unsafe {
- let p = u.get_ptr();
- let cstr = CStr::from_ptr(p);
- assert_eq!(cstr.to_str().unwrap(), "file:///example.txt");
- }
- }
-}
diff --git a/librsvg/color_utils.rs b/librsvg/color_utils.rs
deleted file mode 100644
index 7f2c4279..00000000
--- a/librsvg/color_utils.rs
+++ /dev/null
@@ -1,179 +0,0 @@
-use std::ffi::CStr;
-
-use rsvg_internals::{Color, Parse};
-
-// There are two quirks here:
-//
-// First, we need to expose the Color algebraic type *and* a parse
-// error to C, but we can't repr(C) them plainly. So, we define a
-// ColorKind enum and a ColorSpec struct that can both be represented
-// in C.
-//
-// Second, the C code in librsvg expects ARGB colors passed around as
-// guint32. However, in Rust we'd prefer to use cssparser's RGBA
-// structure, which has explicit fields for red/green/blue/alpha.
-// We'll do those conversions here, for the benefit of the C code, and
-// then just wait until the C code gradually disappears.
-
-// Keep this in sync with rsvg-css.h:RsvgCssColorKind
-#[repr(C)]
-#[derive(Clone, Copy, PartialEq, Debug)]
-enum ColorKind {
- ARGB,
- ParseError,
-}
-
-// Keep this in sync with rsvg-css.h:RsvgCssColorSpec
-#[repr(C)]
-#[derive(Clone, Copy, PartialEq, Debug)]
-pub struct ColorSpec {
- kind: ColorKind,
- argb: u32,
-}
-
-fn rgba_to_argb(r: u8, g: u8, b: u8, a: u8) -> u32 {
- u32::from(a) << 24 | u32::from(r) << 16 | u32::from(g) << 8 | u32::from(b)
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_css_parse_color(string: *const libc::c_char) -> ColorSpec {
- let s = CStr::from_ptr(string).to_string_lossy();
- let r = <Color as Parse>::parse_str(&s);
-
- match r {
- Ok(Color::RGBA(rgba)) => ColorSpec {
- kind: ColorKind::ARGB,
- argb: rgba_to_argb(rgba.red, rgba.green, rgba.blue, rgba.alpha),
- },
-
- _ => ColorSpec {
- kind: ColorKind::ParseError,
- argb: 0,
- },
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use glib::translate::*;
-
- fn parse(s: &str) -> ColorSpec {
- unsafe { rsvg_css_parse_color(s.to_glib_none().0) }
- }
-
- #[test]
- fn parses_hash_hex_colors() {
- assert_eq!(
- parse("#AB10fa20"),
- ColorSpec {
- kind: ColorKind::ARGB,
- argb: 0x20ab10fa,
- }
- );
- assert_eq!(
- parse("#10fa20"),
- ColorSpec {
- kind: ColorKind::ARGB,
- argb: 0xff10fa20,
- }
- );
- assert_eq!(
- parse("#abcd"),
- ColorSpec {
- kind: ColorKind::ARGB,
- argb: 0xddaabbcc,
- }
- );
- assert_eq!(
- parse("#123"),
- ColorSpec {
- kind: ColorKind::ARGB,
- argb: 0xff112233,
- }
- );
- }
-
- #[test]
- fn parses_color_keywords() {
- assert_eq!(
- parse("red"),
- ColorSpec {
- kind: ColorKind::ARGB,
- argb: 0xffff0000,
- }
- );
- assert_eq!(
- parse("lime"),
- ColorSpec {
- kind: ColorKind::ARGB,
- argb: 0xff00ff00,
- }
- );
- assert_eq!(
- parse("blue"),
- ColorSpec {
- kind: ColorKind::ARGB,
- argb: 0xff0000ff,
- }
- );
- }
-
- #[test]
- fn parses_color_functions() {
- assert_eq!(
- parse("rgb(255, 0, 0)"),
- ColorSpec {
- kind: ColorKind::ARGB,
- argb: 0xffff0000,
- }
- );
- assert_eq!(
- parse("rgb(0, 255, 0)"),
- ColorSpec {
- kind: ColorKind::ARGB,
- argb: 0xff00ff00,
- }
- );
- assert_eq!(
- parse("rgb(0, 0, 255)"),
- ColorSpec {
- kind: ColorKind::ARGB,
- argb: 0xff0000ff,
- }
- );
- }
-
- #[test]
- fn current_color_is_error() {
- assert_eq!(
- parse("currentColor"),
- ColorSpec {
- kind: ColorKind::ParseError,
- argb: 0,
- }
- );
- }
-
- fn make_error() -> ColorSpec {
- ColorSpec {
- kind: ColorKind::ParseError,
- argb: 0,
- }
- }
-
- #[test]
- fn invalid_hash_hex_colors_yield_error() {
- assert_eq!(parse("#"), make_error());
- assert_eq!(parse("#xyz"), make_error());
- assert_eq!(parse("#112233gg"), make_error());
- }
-
- #[test]
- fn invalid_colors_yield_error() {
- assert_eq!(parse(""), make_error());
- assert_eq!(parse("foo"), make_error());
- assert_eq!(parse("rgb(chilaquil)"), make_error());
- assert_eq!(parse("rgb(1, 2, 3, 4, 5)"), make_error());
- }
-}
diff --git a/librsvg/dpi.rs b/librsvg/dpi.rs
deleted file mode 100644
index c27667d8..00000000
--- a/librsvg/dpi.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-//! Legacy C API for setting a default DPI (dots per inch = DPI).
-//!
-//! There are two deprecated functions, `rsvg_set_default_dpi` and
-//! `rsvg_set_default_dpi_x_y`, which set global values for the default DPI to be used
-//! with `RsvgHandle`. In turn, `RsvgHandle` assumes that when its own DPI value is set
-//! to `0.0` (which is in fact its default), it will fall back to the global DPI.
-//!
-//! This is clearly not thread-safe, but it is the legacy behavior.
-//!
-//! This module encapsulates that behavior so that the `rsvg_internals` crate
-//! can always have immutable DPI values as intended.
-
-// This is configurable at runtime
-const DEFAULT_DPI_X: f64 = 90.0;
-const DEFAULT_DPI_Y: f64 = 90.0;
-
-static mut DPI_X: f64 = DEFAULT_DPI_X;
-static mut DPI_Y: f64 = DEFAULT_DPI_Y;
-
-#[derive(Debug, Copy, Clone, Default)]
-pub(crate) struct Dpi {
- x: f64,
- y: f64,
-}
-
-impl Dpi {
- pub(crate) fn new(x: f64, y: f64) -> Dpi {
- Dpi { x, y }
- }
-
- pub(crate) fn x(&self) -> f64 {
- if self.x <= 0.0 {
- unsafe { DPI_X }
- } else {
- self.x
- }
- }
-
- pub(crate) fn y(&self) -> f64 {
- if self.y <= 0.0 {
- unsafe { DPI_Y }
- } else {
- self.y
- }
- }
-}
-
-impl From<Dpi> for rsvg_internals::Dpi {
- fn from(dpi: Dpi) -> rsvg_internals::Dpi {
- rsvg_internals::Dpi::new(dpi.x(), dpi.y())
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_set_default_dpi_x_y(dpi_x: libc::c_double, dpi_y: libc::c_double) {
- if dpi_x <= 0.0 {
- DPI_X = DEFAULT_DPI_X;
- } else {
- DPI_X = dpi_x;
- }
-
- if dpi_y <= 0.0 {
- DPI_Y = DEFAULT_DPI_Y;
- } else {
- DPI_Y = dpi_y;
- }
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_set_default_dpi(dpi: libc::c_double) {
- if dpi <= 0.0 {
- DPI_X = DEFAULT_DPI_X;
- DPI_Y = DEFAULT_DPI_Y;
- } else {
- DPI_X = dpi;
- DPI_Y = dpi;
- }
-}
diff --git a/librsvg/messages.rs b/librsvg/messages.rs
deleted file mode 100644
index 9157184d..00000000
--- a/librsvg/messages.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-use glib::translate::*;
-use glib_sys::{g_log_structured_array, GLogField, G_LOG_LEVEL_CRITICAL, G_LOG_LEVEL_WARNING};
-
-/*
- G_LOG_LEVEL_CRITICAL = 1 << 3,
- G_LOG_LEVEL_WARNING = 1 << 4,
-
-#define g_critical(...) g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, \
- __FILE__, G_STRINGIFY (__LINE__), \
- G_STRFUNC, __VA_ARGS__)
-#define g_warning(...) g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, \
- __FILE__, G_STRINGIFY (__LINE__), \
- G_STRFUNC, __VA_ARGS__)
- GLogField fields[] =
- {
- { "PRIORITY", log_level_to_priority (log_level), -1 },
- { "CODE_FILE", file, -1 },
- { "CODE_LINE", line, -1 },
- { "CODE_FUNC", func, -1 },
- /* Filled in later: */
- { "MESSAGE", NULL, -1 },
- /* If @log_domain is %NULL, we will not pass this field: */
- { "GLIB_DOMAIN", log_domain, -1 },
- };
-
- g_log_structured_array (log_level, fields, n_fields);
- */
-
-/// Helper for `rsvg_g_warning` and `rsvg_g_critical`
-///
-/// This simulates what in C would be a call to the g_warning() or g_critical()
-/// macros, but with the underlying function g_log_structured_array().
-///
-/// If the implementation of g_warning() or g_critical() changes, we'll have
-/// to change this function.
-fn rsvg_g_log(level: glib_sys::GLogLevelFlags, msg: &str) {
- // stolen from gmessages.c:log_level_to_priority()
- let priority = match level {
- G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL => b"4\0",
- _ => unreachable!("please add another log level priority to rsvg_g_log()"),
- };
-
- let c_msg = msg.to_glib_none();
- let c_char_msg: *const libc::c_char = c_msg.0;
-
- // Glib's g_log_structured_standard() adds a few more fields for the source
- // file, line number, etc., but those are not terribly useful without a stack
- // trace. So, we'll omit them.
- let fields = [
- GLogField {
- key: b"PRIORITY\0" as *const u8 as *const _,
- value: priority as *const u8 as *const _,
- length: -1,
- },
- GLogField {
- key: b"MESSAGE\0" as *const u8 as *const _,
- value: c_char_msg as *const _,
- length: msg.len() as _,
- },
- // This is the G_LOG_DOMAIN set from the Makefile
- GLogField {
- key: b"GLIB_DOMAIN\0" as *const u8 as *const _,
- value: b"librsvg\0" as *const u8 as *const _,
- length: -1,
- },
- ];
-
- unsafe {
- g_log_structured_array(level, fields.as_ptr(), fields.len());
- }
-}
-
-pub(crate) fn rsvg_g_warning(msg: &str) {
- rsvg_g_log(glib_sys::G_LOG_LEVEL_WARNING, msg);
-}
-
-pub(crate) fn rsvg_g_critical(msg: &str) {
- rsvg_g_log(glib_sys::G_LOG_LEVEL_CRITICAL, msg);
-}
-
-// Once Rust has a function! macro that gives us the current function name, we
-// can remove the $func_name argument.
-#[macro_export]
-macro_rules! rsvg_return_if_fail {
- {
- $func_name:ident;
- $($condition:expr,)+
- } => {
- $(
- if !$condition {
- glib_sys::g_return_if_fail_warning(
- b"librsvg\0" as *const u8 as *const _,
- concat!(stringify!($func_name), "\0").as_ptr() as *const _,
- concat!(stringify!($condition), "\0").as_ptr() as *const _,
- );
- return;
- }
- )+
- }
-}
-
-#[macro_export]
-macro_rules! rsvg_return_val_if_fail {
- {
- $func_name:ident => $retval:expr;
- $($condition:expr,)+
- } => {
- $(
- if !$condition {
- glib_sys::g_return_if_fail_warning(
- b"librsvg\0" as *const u8 as *const _,
- concat!(stringify!($func_name), "\0").as_ptr() as *const _,
- concat!(stringify!($condition), "\0").as_ptr() as *const _,
- );
- return $retval;
- }
- )+
- }
-}
diff --git a/librsvg/pixbuf_utils.rs b/librsvg/pixbuf_utils.rs
deleted file mode 100644
index 3766cea3..00000000
--- a/librsvg/pixbuf_utils.rs
+++ /dev/null
@@ -1,365 +0,0 @@
-//! Legacy C API for functions that render directly to a `GdkPixbuf`.
-//!
-//! This is the implementation of the `rsvg_pixbuf_*` family of functions.
-
-use std::path::PathBuf;
-use std::ptr;
-
-use gdk_pixbuf::{Colorspace, Pixbuf};
-use glib::translate::*;
-use librsvg::{CairoRenderer, Loader};
-use rgb::FromSlice;
-
-use crate::c_api::checked_i32;
-use crate::dpi::Dpi;
-use crate::sizing::LegacySize;
-
-use rsvg_internals::{
- surface_utils::shared_surface::{SharedImageSurface, SurfaceType},
- surface_utils::{Pixel, PixelOps},
- RenderingError,
-};
-
-use crate::c_api::set_gerror;
-
-fn pixbuf_new(width: i32, height: i32) -> Result<Pixbuf, RenderingError> {
- assert!(width > 0 && height > 0);
-
- Pixbuf::new(Colorspace::Rgb, true, 8, width, height).ok_or(RenderingError::OutOfMemory)
-}
-
-pub fn empty_pixbuf() -> Result<Pixbuf, RenderingError> {
- // GdkPixbuf does not allow zero-sized pixbufs, but Cairo allows zero-sized
- // surfaces. In this case, return a 1-pixel transparent pixbuf.
-
- let pixbuf = pixbuf_new(1, 1)?;
- pixbuf.put_pixel(0, 0, 0, 0, 0, 0);
-
- Ok(pixbuf)
-}
-
-pub fn pixbuf_from_surface(surface: &SharedImageSurface) -> Result<Pixbuf, RenderingError> {
- let width = surface.width();
- let height = surface.height();
-
- let pixbuf = pixbuf_new(width, height)?;
- assert!(pixbuf.get_colorspace() == Colorspace::Rgb);
- assert!(pixbuf.get_bits_per_sample() == 8);
- assert!(pixbuf.get_n_channels() == 4);
-
- let pixels = unsafe { pixbuf.get_pixels() };
- let stride = pixbuf.get_rowstride() as usize;
-
- // We use chunks_mut(), not chunks_exact_mut(), because gdk-pixbuf tends
- // to make the last row *not* have the full stride (i.e. it is
- // only as wide as the pixels in that row).
- let pixbuf_rows = pixels.chunks_mut(stride).take(height as usize);
-
- for (src_row, dest_row) in surface.rows().zip(pixbuf_rows) {
- let row: &mut [Pixel] = dest_row.as_rgba_mut();
-
- for (src, dest) in src_row.iter().zip(row.iter_mut()) {
- *dest = Pixel::from(*src).unpremultiply();
- }
- }
-
- Ok(pixbuf)
-}
-
-enum SizeKind {
- Zoom,
- WidthHeight,
- WidthHeightMax,
- ZoomMax,
-}
-
-struct SizeMode {
- kind: SizeKind,
- x_zoom: f64,
- y_zoom: f64,
- width: i32,
- height: i32,
-}
-
-fn get_final_size(in_width: f64, in_height: f64, size_mode: &SizeMode) -> (f64, f64) {
- if in_width == 0.0 || in_height == 0.0 {
- return (0.0, 0.0);
- }
-
- let mut out_width;
- let mut out_height;
-
- match size_mode.kind {
- SizeKind::Zoom => {
- out_width = size_mode.x_zoom * in_width;
- out_height = size_mode.y_zoom * in_height;
- }
-
- SizeKind::ZoomMax => {
- out_width = size_mode.x_zoom * in_width;
- out_height = size_mode.y_zoom * in_height;
-
- if out_width > f64::from(size_mode.width) || out_height > f64::from(size_mode.height) {
- let zoom_x = f64::from(size_mode.width) / out_width;
- let zoom_y = f64::from(size_mode.height) / out_height;
- let zoom = zoom_x.min(zoom_y);
-
- out_width *= zoom;
- out_height *= zoom;
- }
- }
-
- SizeKind::WidthHeightMax => {
- let zoom_x = f64::from(size_mode.width) / in_width;
- let zoom_y = f64::from(size_mode.height) / in_height;
-
- let zoom = zoom_x.min(zoom_y);
-
- out_width = zoom * in_width;
- out_height = zoom * in_height;
- }
-
- SizeKind::WidthHeight => {
- if size_mode.width != -1 {
- out_width = f64::from(size_mode.width);
- } else {
- out_width = in_width;
- }
-
- if size_mode.height != -1 {
- out_height = f64::from(size_mode.height);
- } else {
- out_height = in_height;
- }
- }
- }
-
- (out_width, out_height)
-}
-
-fn render_to_pixbuf_at_size(
- renderer: &CairoRenderer,
- document_width: f64,
- document_height: f64,
- desired_width: f64,
- desired_height: f64,
-) -> Result<Pixbuf, RenderingError> {
- if desired_width == 0.0
- || desired_height == 0.0
- || document_width == 0.0
- || document_height == 0.0
- {
- return empty_pixbuf();
- }
-
- let surface = cairo::ImageSurface::create(
- cairo::Format::ARgb32,
- checked_i32(desired_width.round())?,
- checked_i32(desired_height.round())?,
- )?;
-
- {
- let cr = cairo::Context::new(&surface);
- cr.scale(
- desired_width / document_width,
- desired_height / document_height,
- );
-
- let viewport = cairo::Rectangle {
- x: 0.0,
- y: 0.0,
- width: document_width,
- height: document_height,
- };
-
- // We do it with a cr transform so we can scale non-proportionally.
- renderer.render_document(&cr, &viewport)?;
- }
-
- let shared_surface = SharedImageSurface::wrap(surface, SurfaceType::SRgb)?;
-
- pixbuf_from_surface(&shared_surface)
-}
-
-unsafe fn pixbuf_from_file_with_size_mode(
- filename: *const libc::c_char,
- size_mode: &SizeMode,
- error: *mut *mut glib_sys::GError,
-) -> *mut gdk_pixbuf_sys::GdkPixbuf {
- let path = PathBuf::from_glib_none(filename);
-
- let handle = match Loader::new().read_path(path) {
- Ok(handle) => handle,
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- return ptr::null_mut();
- }
- };
-
- let dpi = Dpi::default();
- let renderer = CairoRenderer::new(&handle).with_dpi(dpi.x(), dpi.y());
-
- let (document_width, document_height) = match renderer.legacy_document_size_in_pixels() {
- Ok(dim) => dim,
- Err(e) => {
- set_gerror(error, 0, &format!("{}", e));
- return ptr::null_mut();
- }
- };
-
- let (desired_width, desired_height) =
- get_final_size(document_width, document_height, size_mode);
-
- render_to_pixbuf_at_size(
- &renderer,
- document_width,
- document_height,
- desired_width,
- desired_height,
- )
- .map(|pixbuf| pixbuf.to_glib_full())
- .unwrap_or_else(|e| {
- set_gerror(error, 0, &format!("{}", e));
- ptr::null_mut()
- })
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_pixbuf_from_file(
- filename: *const libc::c_char,
- error: *mut *mut glib_sys::GError,
-) -> *mut gdk_pixbuf_sys::GdkPixbuf {
- rsvg_return_val_if_fail! {
- rsvg_pixbuf_from_file => ptr::null_mut();
-
- !filename.is_null(),
- error.is_null() || (*error).is_null(),
- }
-
- pixbuf_from_file_with_size_mode(
- filename,
- &SizeMode {
- kind: SizeKind::WidthHeight,
- x_zoom: 0.0,
- y_zoom: 0.0,
- width: -1,
- height: -1,
- },
- error,
- )
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_size(
- filename: *const libc::c_char,
- width: libc::c_int,
- height: libc::c_int,
- error: *mut *mut glib_sys::GError,
-) -> *mut gdk_pixbuf_sys::GdkPixbuf {
- rsvg_return_val_if_fail! {
- rsvg_pixbuf_from_file_at_size => ptr::null_mut();
-
- !filename.is_null(),
- (width >= 1 && height >= 1) || (width == -1 && height == -1),
- error.is_null() || (*error).is_null(),
- }
-
- pixbuf_from_file_with_size_mode(
- filename,
- &SizeMode {
- kind: SizeKind::WidthHeight,
- x_zoom: 0.0,
- y_zoom: 0.0,
- width,
- height,
- },
- error,
- )
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_zoom(
- filename: *const libc::c_char,
- x_zoom: libc::c_double,
- y_zoom: libc::c_double,
- error: *mut *mut glib_sys::GError,
-) -> *mut gdk_pixbuf_sys::GdkPixbuf {
- rsvg_return_val_if_fail! {
- rsvg_pixbuf_from_file_at_zoom => ptr::null_mut();
-
- !filename.is_null(),
- x_zoom > 0.0 && y_zoom > 0.0,
- error.is_null() || (*error).is_null(),
- }
-
- pixbuf_from_file_with_size_mode(
- filename,
- &SizeMode {
- kind: SizeKind::Zoom,
- x_zoom,
- y_zoom,
- width: 0,
- height: 0,
- },
- error,
- )
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_zoom_with_max(
- filename: *const libc::c_char,
- x_zoom: libc::c_double,
- y_zoom: libc::c_double,
- max_width: libc::c_int,
- max_height: libc::c_int,
- error: *mut *mut glib_sys::GError,
-) -> *mut gdk_pixbuf_sys::GdkPixbuf {
- rsvg_return_val_if_fail! {
- rsvg_pixbuf_from_file_at_zoom_with_max => ptr::null_mut();
-
- !filename.is_null(),
- x_zoom > 0.0 && y_zoom > 0.0,
- max_width >= 1 && max_height >= 1,
- error.is_null() || (*error).is_null(),
- }
-
- pixbuf_from_file_with_size_mode(
- filename,
- &SizeMode {
- kind: SizeKind::ZoomMax,
- x_zoom,
- y_zoom,
- width: max_width,
- height: max_height,
- },
- error,
- )
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn rsvg_pixbuf_from_file_at_max_size(
- filename: *const libc::c_char,
- max_width: libc::c_int,
- max_height: libc::c_int,
- error: *mut *mut glib_sys::GError,
-) -> *mut gdk_pixbuf_sys::GdkPixbuf {
- rsvg_return_val_if_fail! {
- rsvg_pixbuf_from_file_at_max_size => ptr::null_mut();
-
- !filename.is_null(),
- max_width >= 1 && max_height >= 1,
- error.is_null() || (*error).is_null(),
- }
-
- pixbuf_from_file_with_size_mode(
- filename,
- &SizeMode {
- kind: SizeKind::WidthHeightMax,
- x_zoom: 0.0,
- y_zoom: 0.0,
- width: max_width,
- height: max_height,
- },
- error,
- )
-}
diff --git a/librsvg/sizing.rs b/librsvg/sizing.rs
deleted file mode 100644
index 1e0b996b..00000000
--- a/librsvg/sizing.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-use float_cmp::approx_eq;
-use librsvg::{CairoRenderer, IntrinsicDimensions, Length, RenderingError};
-
-use crate::c_api::unit_rectangle;
-
-pub trait LegacySize {
- /// Returns the SVG's size suitable for the legacy C API.
- ///
- /// The legacy C API can compute an SVG document's size from the
- /// `width`, `height`, and `viewBox` attributes of the toplevel `<svg>`
- /// element. If these are not available, then the size must be computed
- /// by actually measuring the geometries of elements in the document.
- ///
- /// See https://www.w3.org/TR/css-images-3/#sizing-terms for terminology and logic.
- fn legacy_document_size_in_pixels(&self) -> Result<(f64, f64), RenderingError>;
-}
-
-impl<'a> LegacySize for CairoRenderer<'a> {
- fn legacy_document_size_in_pixels(&self) -> Result<(f64, f64), RenderingError> {
- let size_from_intrinsic_dimensions = self.intrinsic_size_in_pixels().or_else(|| {
- size_in_pixels_from_percentage_width_and_height(&self.intrinsic_dimensions())
- });
-
- if let Some(dim) = size_from_intrinsic_dimensions {
- // We have a size directly computed from the <svg> attributes
- Ok(dim)
- } else {
- // Compute the extents of all objects in the SVG
- let (ink_r, _) = self.geometry_for_layer(None, &unit_rectangle())?;
- Ok((ink_r.width, ink_r.height))
- }
- }
-}
-
-/// If the width and height are in percentage units, computes a size equal to the
-/// `viewBox`'s aspect ratio if it exists, or else returns None.
-///
-/// For example, a `viewBox="0 0 100 200"` will yield `Some(100.0, 200.0)`.
-///
-/// Note that this only checks that the width and height are in percentage units, but
-/// it actually ignores their values. This is because at the point this function is
-/// called, there is no viewport to embed the SVG document in, so those percentage
-/// units cannot be resolved against anything in particular. The idea is to return
-/// some dimensions with the correct aspect ratio.
-fn size_in_pixels_from_percentage_width_and_height(
- dim: &IntrinsicDimensions,
-) -> Option<(f64, f64)> {
- let IntrinsicDimensions {
- width,
- height,
- vbox,
- } = *dim;
-
- use librsvg::LengthUnit::*;
-
- // If both width and height are 100%, just use the vbox size as a pixel size.
- // This gives a size with the correct aspect ratio.
-
- match (width, height, vbox) {
- (None, None, Some(vbox)) => Some((vbox.width, vbox.height)),
-
- (
- Some(Length {
- length: w,
- unit: Percent,
- }),
- Some(Length {
- length: h,
- unit: Percent,
- }),
- Some(vbox),
- ) if approx_eq!(f64, w, 1.0) && approx_eq!(f64, h, 1.0) => Some((vbox.width, vbox.height)),
-
- _ => None,
- }
-}