[librsvg] Move the mutable LoadState into CHandle
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] Move the mutable LoadState into CHandle
- Date: Tue, 9 Apr 2019 16:45:40 +0000 (UTC)
commit 90f5d0623108dbbc43ab0c59591e2599d05cc187
Author: Federico Mena Quintero <federico gnome org>
Date: Tue Apr 9 11:34:07 2019 -0500
Move the mutable LoadState into CHandle
This looks like a lot of churn, but here's basically what happened:
We used to have
struct Handle {
... fields with interior mutability ...
load_state: Cell<LoadState> // a simple enum
}
Now we have this:
struct CHandle {
... fields with interior mutability ...
load_state: RefCell<LoadState> // a complex enum
}
enum LoadState {
Start,
Loading { buffer: Vec<u8> },
ClosedOk { handle: Handle },
ClosedError,
}
struct Handle {
... only immutable fields ...
}
Here, CHandle now encapsulates all the interior mutability for the
purposes of the C API, and Handle is created immutable.
CHandle does all the checking of load_state to ensure the C API is
called in the correct sequence, and so that (e.g.) a handle is not
queried for dimensions until it is loaded.
In theory we could now have an rsvg_internals crate with a "clean"
immutable API, and a small helper crate just for the purposes of the C
API.
librsvg_crate/src/lib.rs | 14 +-
rsvg_internals/src/c_api.rs | 318 ++++++++++++++++++++++++++-----------
rsvg_internals/src/handle.rs | 168 ++++----------------
rsvg_internals/src/pixbuf_utils.rs | 24 ++-
4 files changed, 272 insertions(+), 252 deletions(-)
---
diff --git a/librsvg_crate/src/lib.rs b/librsvg_crate/src/lib.rs
index 3d8dbd26..7cfc7dcc 100644
--- a/librsvg_crate/src/lib.rs
+++ b/librsvg_crate/src/lib.rs
@@ -279,8 +279,6 @@ impl Loader {
base_file: Option<&gio::File>,
cancellable: P,
) -> Result<SvgHandle, LoadingError> {
- let handle = Handle::new();
-
let base_url = if let Some(base_file) = base_file {
Some(url_from_file(&base_file)?)
} else {
@@ -289,9 +287,11 @@ impl Loader {
let load_options = LoadOptions::new(self.load_flags(), base_url);
- handle.read_stream_sync(&load_options, stream, cancellable.into())?;
-
- Ok(SvgHandle(handle))
+ Ok(SvgHandle(Handle::from_stream(
+ &load_options,
+ stream,
+ cancellable.into(),
+ )?))
}
}
@@ -396,7 +396,7 @@ impl<'a> CairoRenderer<'a> {
) -> Result<(cairo::Rectangle, cairo::Rectangle), RenderingError> {
self.handle
.0
- .get_geometry_for_element(id, viewport, self.dpi)
+ .get_geometry_for_element(id, viewport, self.dpi, false)
.map(|(i, l)| (i.into(), l.into()))
}
@@ -408,6 +408,6 @@ impl<'a> CairoRenderer<'a> {
) -> Result<(), RenderingError> {
self.handle
.0
- .render_element_to_viewport(cr, id, viewport, self.dpi)
+ .render_element_to_viewport(cr, id, viewport, self.dpi, false)
}
}
diff --git a/rsvg_internals/src/c_api.rs b/rsvg_internals/src/c_api.rs
index 8c80a00d..0a7bde4f 100644
--- a/rsvg_internals/src/c_api.rs
+++ b/rsvg_internals/src/c_api.rs
@@ -1,4 +1,4 @@
-use std::cell::{Cell, RefCell};
+use std::cell::{Cell, Ref, RefCell, RefMut};
use std::ffi::{CStr, CString};
use std::ops;
use std::path::PathBuf;
@@ -7,7 +7,9 @@ use std::slice;
use std::sync::Once;
use std::{f64, i32};
+use gdk_pixbuf::Pixbuf;
use libc;
+use url::Url;
use gio::prelude::*;
@@ -17,17 +19,18 @@ use glib::subclass::object::ObjectClassSubclassExt;
use glib::subclass::prelude::*;
use glib::translate::*;
use glib::value::{FromValue, FromValueOptional, SetValue};
-use glib::{Cast, ParamFlags, ParamSpec, StaticType, ToValue, Type, Value};
+use glib::{Bytes, Cast, ParamFlags, ParamSpec, StaticType, ToValue, Type, Value};
use glib_sys;
use gobject_sys::{self, GEnumValue, GFlagsValue};
use crate::dpi::Dpi;
use crate::drawing_ctx::RsvgRectangle;
-use crate::error::{set_gerror, LoadingError, RSVG_ERROR_FAILED};
-use crate::handle::{Handle, LoadFlags, LoadOptions, LoadState};
+use crate::error::{set_gerror, LoadingError, RenderingError, RSVG_ERROR_FAILED};
+use crate::handle::{Handle, LoadFlags, LoadOptions};
use crate::length::RsvgLength;
-use url::Url;
+use crate::structure::IntrinsicDimensions;
+use crate::util::rsvg_g_warning;
mod handle_flags {
// The following is entirely stolen from the auto-generated code
@@ -211,6 +214,18 @@ impl Drop for SizeCallback {
}
}
+enum LoadState {
+ // Just created the CHandle
+ Start,
+
+ // Being loaded using the legacy write()/close() API
+ Loading { buffer: Vec<u8> },
+
+ ClosedOk { handle: Handle },
+
+ ClosedError,
+}
+
/// Contains all the interior mutability for a RsvgHandle to be called
/// from the C API.
pub struct CHandle {
@@ -219,7 +234,8 @@ pub struct CHandle {
base_url: RefCell<Option<Url>>,
base_url_cstring: RefCell<Option<CString>>, // needed because the C api returns *const char
size_callback: RefCell<SizeCallback>,
- handle: Handle,
+ is_testing: Cell<bool>,
+ load_state: RefCell<LoadState>,
}
unsafe impl ClassStruct for RsvgHandleClass {
@@ -350,7 +366,8 @@ impl ObjectSubclass for CHandle {
base_url: RefCell::new(None),
base_url_cstring: RefCell::new(None),
size_callback: RefCell::new(SizeCallback::default()),
- handle: Handle::new(),
+ is_testing: Cell::new(false),
+ load_state: RefCell::new(LoadState::Start),
}
}
}
@@ -415,24 +432,29 @@ impl ObjectImpl for CHandle {
.to_value()),
subclass::Property("width", ..) => Ok(self
- .handle
- .get_dimensions_no_error(self.dpi.get(), &*size_callback)
+ .get_handle_ref()
+ .unwrap()
+ .get_dimensions_no_error(self.dpi.get(), &*size_callback, self.is_testing.get())
.width
.to_value()),
+
subclass::Property("height", ..) => Ok(self
- .handle
- .get_dimensions_no_error(self.dpi.get(), &*size_callback)
+ .get_handle_ref()
+ .unwrap()
+ .get_dimensions_no_error(self.dpi.get(), &*size_callback, self.is_testing.get())
.height
.to_value()),
subclass::Property("em", ..) => Ok(self
- .handle
- .get_dimensions_no_error(self.dpi.get(), &*size_callback)
+ .get_handle_ref()
+ .unwrap()
+ .get_dimensions_no_error(self.dpi.get(), &*size_callback, self.is_testing.get())
.em
.to_value()),
subclass::Property("ex", ..) => Ok(self
- .handle
- .get_dimensions_no_error(self.dpi.get(), &*size_callback)
+ .get_handle_ref()
+ .unwrap()
+ .get_dimensions_no_error(self.dpi.get(), &*size_callback, self.is_testing.get())
.ex
.to_value()),
@@ -503,6 +525,177 @@ impl CHandle {
in_loop: Cell::new(false),
};
}
+
+ 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);
+ }
+
+ _ => panic!("Handle must not be closed in order to write to it"),
+ }
+ }
+
+ fn close(&self) -> Result<(), LoadingError> {
+ 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);
+
+ self.read_stream(state, &stream.upcast(), 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();
+
+ match *state {
+ LoadState::Start => self.read_stream(state, stream, cancellable),
+ LoadState::Loading { .. } | LoadState::ClosedOk { .. } | LoadState::ClosedError => {
+ panic!(
+ "handle must not be already loaded in order to call rsvg_handle_read_stream_sync()",
+ )
+ }
+ }
+ }
+
+ fn read_stream(
+ &self,
+ mut load_state: RefMut<LoadState>,
+ stream: &gio::InputStream,
+ cancellable: Option<&gio::Cancellable>,
+ ) -> Result<(), LoadingError> {
+ match Handle::from_stream(&self.load_options(), stream, cancellable) {
+ Ok(handle) => {
+ *load_state = LoadState::ClosedOk { handle };
+ Ok(())
+ }
+
+ Err(e) => {
+ *load_state = LoadState::ClosedError;
+ Err(e)
+ }
+ }
+ }
+
+ fn get_handle_ref(&self) -> Result<Ref<Handle>, RenderingError> {
+ let state = self.load_state.borrow();
+
+ match *state {
+ LoadState::Start => {
+ rsvg_g_warning("Handle has not been loaded");
+ Err(RenderingError::HandleIsNotLoaded)
+ }
+
+ LoadState::Loading { .. } => {
+ rsvg_g_warning("Handle is still loading; call rsvg_handle_close() first");
+ Err(RenderingError::HandleIsNotLoaded)
+ }
+
+ LoadState::ClosedError => {
+ rsvg_g_warning(
+ "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 has_sub(&self, id: &str) -> Result<bool, RenderingError> {
+ let handle = self.get_handle_ref()?;
+ handle.has_sub(id)
+ }
+
+ fn get_dimensions(&self) -> RsvgDimensionData {
+ if let Ok(handle) = self.get_handle_ref() {
+ let size_callback = self.size_callback.borrow();
+ handle.get_dimensions_no_error(self.dpi.get(), &*size_callback, self.is_testing.get())
+ } else {
+ panic!("Handle is not loaded");
+ }
+ }
+
+ fn get_dimensions_sub(&self, id: Option<&str>) -> Result<RsvgDimensionData, RenderingError> {
+ let handle = self.get_handle_ref()?;
+ let size_callback = self.size_callback.borrow();
+ handle.get_dimensions_sub(id, self.dpi.get(), &*size_callback, self.is_testing.get())
+ }
+
+ fn get_position_sub(&self, id: Option<&str>) -> Result<RsvgPositionData, RenderingError> {
+ let handle = self.get_handle_ref()?;
+ let size_callback = self.size_callback.borrow();
+ handle.get_position_sub(id, self.dpi.get(), &*size_callback, self.is_testing.get())
+ }
+
+ fn render_cairo_sub(
+ &self,
+ cr: &cairo::Context,
+ id: Option<&str>,
+ ) -> Result<(), RenderingError> {
+ let handle = self.get_handle_ref()?;
+ let size_callback = self.size_callback.borrow();
+ handle.render_cairo_sub(
+ cr,
+ id,
+ self.dpi.get(),
+ &*size_callback,
+ self.is_testing.get(),
+ )
+ }
+
+ fn get_pixbuf_sub(&self, id: Option<&str>) -> Result<Pixbuf, RenderingError> {
+ let handle = self.get_handle_ref()?;
+ let size_callback = self.size_callback.borrow();
+ handle.get_pixbuf_sub(id, self.dpi.get(), &*size_callback, self.is_testing.get())
+ }
+
+ fn get_geometry_for_element(
+ &self,
+ id: Option<&str>,
+ viewport: &cairo::Rectangle,
+ ) -> Result<(RsvgRectangle, RsvgRectangle), RenderingError> {
+ let handle = self.get_handle_ref()?;
+ handle.get_geometry_for_element(id, viewport, self.dpi.get(), self.is_testing.get())
+ }
+
+ fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
+ let handle = self.get_handle_ref().unwrap();
+ handle.get_intrinsic_dimensions()
+ }
+
+ fn set_testing(&self, is_testing: bool) {
+ self.is_testing.set(is_testing);
+ }
}
pub fn get_rust_handle<'a>(handle: *const RsvgHandle) -> &'a CHandle {
@@ -700,7 +893,7 @@ pub unsafe extern "C" fn rsvg_rust_handle_set_testing(
) {
let rhandle = get_rust_handle(raw_handle);
- rhandle.handle.set_testing(from_glib(testing));
+ rhandle.set_testing(from_glib(testing));
}
#[no_mangle]
@@ -712,17 +905,10 @@ pub unsafe extern "C" fn rsvg_rust_handle_read_stream_sync(
) -> glib_sys::gboolean {
let rhandle = get_rust_handle(handle);
- if rhandle.handle.load_state() != LoadState::Start {
- panic!("handle must not be already loaded in order to call rsvg_handle_read_stream_sync()",);
- }
-
let stream = from_glib_none(stream);
let cancellable: Option<gio::Cancellable> = from_glib_none(cancellable);
- match rhandle
- .handle
- .read_stream_sync(&rhandle.load_options(), &stream, cancellable.as_ref())
- {
+ match rhandle.read_stream_sync(&stream, cancellable.as_ref()) {
Ok(()) => true.to_glib(),
Err(e) => {
@@ -739,16 +925,8 @@ pub unsafe extern "C" fn rsvg_rust_handle_write(
count: usize,
) {
let rhandle = get_rust_handle(handle);
-
- let load_state = rhandle.handle.load_state();
-
- if !(load_state == LoadState::Start || load_state == LoadState::Loading) {
- panic!("handle must not be closed in order to write to it");
- }
-
let buffer = slice::from_raw_parts(buf, count);
-
- rhandle.handle.write(buffer);
+ rhandle.write(buffer);
}
#[no_mangle]
@@ -758,7 +936,7 @@ pub unsafe extern "C" fn rsvg_rust_handle_close(
) -> glib_sys::gboolean {
let rhandle = get_rust_handle(handle);
- match rhandle.handle.close(&rhandle.load_options()) {
+ match rhandle.close() {
Ok(()) => true.to_glib(),
Err(e) => {
@@ -780,7 +958,7 @@ pub unsafe extern "C" fn rsvg_rust_handle_has_sub(
let id: String = from_glib_none(id);
// FIXME: return a proper error code to the public API
- rhandle.handle.has_sub(&id).unwrap_or(false).to_glib()
+ rhandle.has_sub(&id).unwrap_or(false).to_glib()
}
#[no_mangle]
@@ -793,14 +971,7 @@ pub unsafe extern "C" fn rsvg_rust_handle_render_cairo_sub(
let cr = from_glib_none(cr);
let id: Option<String> = from_glib_none(id);
- let size_callback = rhandle.size_callback.borrow();
-
- match rhandle.handle.render_cairo_sub(
- &cr,
- id.as_ref().map(String::as_str),
- rhandle.dpi.get(),
- &*size_callback,
- ) {
+ match rhandle.render_cairo_sub(&cr, id.as_ref().map(String::as_str)) {
Ok(()) => true.to_glib(),
Err(_) => {
@@ -818,13 +989,7 @@ pub unsafe extern "C" fn rsvg_rust_handle_get_pixbuf_sub(
let rhandle = get_rust_handle(handle);
let id: Option<String> = from_glib_none(id);
- let size_callback = rhandle.size_callback.borrow();
-
- match rhandle.handle.get_pixbuf_sub(
- id.as_ref().map(String::as_str),
- rhandle.dpi.get(),
- &*size_callback,
- ) {
+ match rhandle.get_pixbuf_sub(id.as_ref().map(String::as_str)) {
Ok(pixbuf) => pixbuf.to_glib_full(),
Err(_) => ptr::null_mut(),
}
@@ -836,12 +1001,7 @@ pub unsafe extern "C" fn rsvg_rust_handle_get_dimensions(
dimension_data: *mut RsvgDimensionData,
) {
let rhandle = get_rust_handle(handle);
-
- let size_callback = rhandle.size_callback.borrow();
-
- *dimension_data = rhandle
- .handle
- .get_dimensions_no_error(rhandle.dpi.get(), &*size_callback);
+ *dimension_data = rhandle.get_dimensions();
}
#[no_mangle]
@@ -854,13 +1014,7 @@ pub unsafe extern "C" fn rsvg_rust_handle_get_dimensions_sub(
let id: Option<String> = from_glib_none(id);
- let size_callback = rhandle.size_callback.borrow();
-
- match rhandle.handle.get_dimensions_sub(
- id.as_ref().map(String::as_str),
- rhandle.dpi.get(),
- &*size_callback,
- ) {
+ match rhandle.get_dimensions_sub(id.as_ref().map(String::as_str)) {
Ok(dimensions) => {
*dimension_data = dimensions;
true.to_glib()
@@ -890,13 +1044,7 @@ pub unsafe extern "C" fn rsvg_rust_handle_get_position_sub(
let id: Option<String> = from_glib_none(id);
- let size_callback = rhandle.size_callback.borrow();
-
- match rhandle.handle.get_position_sub(
- id.as_ref().map(String::as_str),
- rhandle.dpi.get(),
- &*size_callback,
- ) {
+ match rhandle.get_position_sub(id.as_ref().map(String::as_str)) {
Ok(position) => {
*position_data = position;
true.to_glib()
@@ -962,13 +1110,7 @@ pub unsafe extern "C" fn rsvg_rust_handle_new_from_gfile_sync(
let res = file
.read(cancellable.as_ref())
.map_err(|e| LoadingError::from(e))
- .and_then(|stream| {
- rhandle.handle.read_stream_sync(
- &rhandle.load_options(),
- &stream.upcast(),
- cancellable.as_ref(),
- )
- });
+ .and_then(|stream| rhandle.read_stream_sync(&stream.upcast(), cancellable.as_ref()));
match res {
Ok(()) => raw_handle,
@@ -1001,11 +1143,7 @@ pub unsafe extern "C" fn rsvg_rust_handle_new_from_stream_sync(
let stream = from_glib_none(input_stream);
let cancellable: Option<gio::Cancellable> = from_glib_none(cancellable);
- match rhandle.handle.read_stream_sync(
- &rhandle.load_options(),
- &stream,
- cancellable.as_ref(),
- ) {
+ match rhandle.read_stream_sync(&stream, cancellable.as_ref()) {
Ok(()) => raw_handle,
Err(e) => {
@@ -1081,11 +1219,7 @@ pub unsafe extern "C" fn rsvg_rust_handle_get_intrinsic_dimensions(
) {
let rhandle = get_rust_handle(handle);
- if rhandle.handle.check_is_loaded().is_err() {
- return;
- }
-
- let d = rhandle.handle.get_intrinsic_dimensions();
+ let d = rhandle.get_intrinsic_dimensions();
let w = d.width.map(|l| l.to_length());
let h = d.height.map(|l| l.to_length());
@@ -1107,17 +1241,9 @@ pub unsafe extern "C" fn rsvg_rust_handle_get_geometry_for_element(
) -> glib_sys::gboolean {
let rhandle = get_rust_handle(handle);
- if rhandle.handle.check_is_loaded().is_err() {
- return false.to_glib();
- }
-
let id: Option<String> = from_glib_none(id);
- match rhandle.handle.get_geometry_for_element(
- id.as_ref().map(String::as_str),
- &viewport.into(),
- rhandle.dpi.get(),
- ) {
+ match rhandle.get_geometry_for_element(id.as_ref().map(String::as_str), &viewport.into()) {
Ok((ink_rect, logical_rect)) => {
if !out_ink_rect.is_null() {
*out_ink_rect = ink_rect;
diff --git a/rsvg_internals/src/handle.rs b/rsvg_internals/src/handle.rs
index aaedb36f..a2c7f50a 100644
--- a/rsvg_internals/src/handle.rs
+++ b/rsvg_internals/src/handle.rs
@@ -1,10 +1,9 @@
-use std::cell::{Cell, RefCell};
use std::rc::Rc;
use cairo::{self, ImageSurface, Status};
use gdk_pixbuf::Pixbuf;
use gio;
-use glib::{self, Bytes, Cast};
+use glib;
use libc;
use locale_config::{LanguageRange, Locale};
@@ -63,124 +62,22 @@ impl LoadOptions {
}
}
-#[derive(Copy, Clone, PartialEq)]
-pub enum LoadState {
- Start,
- Loading,
- ClosedOk,
- ClosedError,
-}
-
pub struct Handle {
- svg: RefCell<Option<Rc<Svg>>>,
- load_state: Cell<LoadState>,
- buffer: RefCell<Vec<u8>>, // used by the legacy write() api
- is_testing: Cell<bool>,
+ svg: Rc<Svg>,
}
impl Handle {
- pub fn new() -> Handle {
- Handle {
- svg: RefCell::new(None),
- load_state: Cell::new(LoadState::Start),
- buffer: RefCell::new(Vec::new()),
- is_testing: Cell::new(false),
- }
- }
-
- fn get_svg(&self) -> Rc<Svg> {
- // This assumes that the Svg is already loaded, or unwrap() will panic
- self.svg.borrow().as_ref().unwrap().clone()
- }
-
- pub fn read_stream_sync(
- &self,
+ pub fn from_stream(
load_options: &LoadOptions,
stream: &gio::InputStream,
cancellable: Option<&gio::Cancellable>,
- ) -> Result<(), LoadingError> {
- self.load_state.set(LoadState::Loading);
-
- let svg = Svg::load_from_stream(load_options, stream, cancellable).map_err(|e| {
- self.load_state.set(LoadState::ClosedError);
- e
- })?;
-
- *self.svg.borrow_mut() = Some(Rc::new(svg));
- self.load_state.set(LoadState::ClosedOk);
- Ok(())
- }
-
- pub fn check_is_loaded(self: &Handle) -> Result<(), RenderingError> {
- match self.load_state.get() {
- LoadState::Start => {
- rsvg_g_warning("RsvgHandle has not been loaded");
- Err(RenderingError::HandleIsNotLoaded)
- }
-
- LoadState::Loading => {
- rsvg_g_warning("RsvgHandle is still loading; call rsvg_handle_close() first");
- Err(RenderingError::HandleIsNotLoaded)
- }
-
- LoadState::ClosedOk => Ok(()),
-
- LoadState::ClosedError => {
- rsvg_g_warning(
- "RsvgHandle could not read or parse the SVG; did you check for errors during \
- the loading stage?",
- );
- Err(RenderingError::HandleIsNotLoaded)
- }
- }
- }
-
- pub fn load_state(&self) -> LoadState {
- self.load_state.get()
- }
-
- pub fn write(&self, buf: &[u8]) {
- match self.load_state.get() {
- LoadState::Start => self.load_state.set(LoadState::Loading),
- LoadState::Loading => (),
- _ => unreachable!(),
- };
-
- self.buffer.borrow_mut().extend_from_slice(buf);
- }
-
- pub fn close(&self, load_options: &LoadOptions) -> Result<(), LoadingError> {
- let res = match self.load_state.get() {
- LoadState::Start => {
- self.load_state.set(LoadState::ClosedError);
- Err(LoadingError::NoDataPassedToParser)
- }
-
- LoadState::Loading => {
- let buffer = self.buffer.borrow();
- let bytes = Bytes::from(&*buffer);
- let stream = gio::MemoryInputStream::new_from_bytes(&bytes);
-
- self.read_stream_sync(load_options, &stream.upcast(), None)
- }
-
- LoadState::ClosedOk | LoadState::ClosedError => {
- // closing is idempotent
- Ok(())
- }
- };
-
- assert!(
- self.load_state.get() == LoadState::ClosedOk
- || self.load_state.get() == LoadState::ClosedError
- );
-
- res
+ ) -> Result<Handle, LoadingError> {
+ Ok(Handle {
+ svg: Rc::new(Svg::load_from_stream(load_options, stream, cancellable)?),
+ })
}
pub fn has_sub(&self, id: &str) -> Result<bool, RenderingError> {
- self.check_is_loaded()?;
-
match self.lookup_node(id) {
Ok(_) => Ok(true),
@@ -194,9 +91,8 @@ impl Handle {
&self,
dpi: Dpi,
size_callback: &SizeCallback,
+ is_testing: bool,
) -> Result<RsvgDimensionData, RenderingError> {
- self.check_is_loaded()?;
-
// 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
@@ -212,7 +108,7 @@ impl Handle {
size_callback.start_loop();
- let res = self.get_dimensions_sub(None, dpi, size_callback);
+ let res = self.get_dimensions_sub(None, dpi, size_callback, is_testing);
size_callback.end_loop();
@@ -223,8 +119,9 @@ impl Handle {
&self,
dpi: Dpi,
size_callback: &SizeCallback,
+ is_testing: bool,
) -> RsvgDimensionData {
- match self.get_dimensions(dpi, size_callback) {
+ match self.get_dimensions(dpi, size_callback, is_testing) {
Ok(dimensions) => dimensions,
Err(_) => {
@@ -245,10 +142,9 @@ impl Handle {
id: Option<&str>,
dpi: Dpi,
size_callback: &SizeCallback,
+ is_testing: bool,
) -> Result<RsvgDimensionData, RenderingError> {
- self.check_is_loaded()?;
-
- let (ink_r, _) = self.get_geometry_sub(id, dpi)?;
+ let (ink_r, _) = self.get_geometry_sub(id, dpi, is_testing)?;
let (w, h) = size_callback.call(ink_r.width as libc::c_int, ink_r.height as libc::c_int);
@@ -265,14 +161,13 @@ impl Handle {
id: Option<&str>,
dpi: Dpi,
size_callback: &SizeCallback,
+ is_testing: bool,
) -> Result<RsvgPositionData, RenderingError> {
- self.check_is_loaded()?;
-
if let None = id {
return Ok(RsvgPositionData { x: 0, y: 0 });
}
- let (ink_r, _) = self.get_geometry_sub(id, dpi)?;
+ let (ink_r, _) = self.get_geometry_sub(id, dpi, is_testing)?;
let width = ink_r.width as libc::c_int;
let height = ink_r.height as libc::c_int;
@@ -285,6 +180,10 @@ impl Handle {
})
}
+ fn get_svg(&self) -> Rc<Svg> {
+ self.svg.clone()
+ }
+
fn get_root(&self) -> RsvgNode {
self.get_svg().root()
}
@@ -295,6 +194,7 @@ impl Handle {
node: &RsvgNode,
viewport: &cairo::Rectangle,
dpi: Dpi,
+ is_testing: bool,
) -> Result<(RsvgRectangle, RsvgRectangle), RenderingError> {
let target = ImageSurface::create(cairo::Format::Rgb24, 1, 1)?;
let cr = cairo::Context::new(&target);
@@ -305,7 +205,7 @@ impl Handle {
viewport,
dpi,
true,
- self.is_testing.get(),
+ is_testing,
);
let root = self.get_root();
@@ -330,6 +230,7 @@ impl Handle {
&self,
id: Option<&str>,
dpi: Dpi,
+ is_testing: bool,
) -> Result<(RsvgRectangle, RsvgRectangle), RenderingError> {
let node = self.get_node_or_root(id)?;
@@ -364,7 +265,7 @@ impl Handle {
height: 1.0,
};
- self.get_node_geometry_with_viewport(&node, &viewport, dpi)
+ self.get_node_geometry_with_viewport(&node, &viewport, dpi, is_testing)
}
fn get_node_or_root(&self, id: Option<&str>) -> Result<RsvgNode, RenderingError> {
@@ -380,9 +281,10 @@ impl Handle {
id: Option<&str>,
viewport: &cairo::Rectangle,
dpi: Dpi,
+ is_testing: bool,
) -> Result<(RsvgRectangle, RsvgRectangle), RenderingError> {
let node = self.get_node_or_root(id)?;
- self.get_node_geometry_with_viewport(&node, viewport, dpi)
+ self.get_node_geometry_with_viewport(&node, viewport, dpi, is_testing)
}
fn lookup_node(&self, id: &str) -> Result<RsvgNode, DefsLookupErrorKind> {
@@ -425,11 +327,11 @@ impl Handle {
id: Option<&str>,
dpi: Dpi,
size_callback: &SizeCallback,
+ is_testing: bool,
) -> Result<(), RenderingError> {
check_cairo_context(cr)?;
- self.check_is_loaded()?;
- let dimensions = self.get_dimensions(dpi, size_callback)?;
+ let dimensions = self.get_dimensions(dpi, size_callback, is_testing)?;
if dimensions.width == 0 || dimensions.height == 0 {
// nothing to render
return Ok(());
@@ -442,7 +344,7 @@ impl Handle {
height: f64::from(dimensions.height),
};
- self.render_element_to_viewport(cr, id, &viewport, dpi)
+ self.render_element_to_viewport(cr, id, &viewport, dpi, is_testing)
}
pub fn render_element_to_viewport(
@@ -451,6 +353,7 @@ impl Handle {
id: Option<&str>,
viewport: &cairo::Rectangle,
dpi: Dpi,
+ is_testing: bool,
) -> Result<(), RenderingError> {
check_cairo_context(cr)?;
@@ -470,7 +373,7 @@ impl Handle {
viewport,
dpi,
false,
- self.is_testing.get(),
+ is_testing,
);
let res = draw_ctx.draw_node_from_stack(&root.get_cascaded_values(), &root, false);
cr.restore();
@@ -483,10 +386,9 @@ impl Handle {
id: Option<&str>,
dpi: Dpi,
size_callback: &SizeCallback,
+ is_testing: bool,
) -> Result<Pixbuf, RenderingError> {
- self.check_is_loaded()?;
-
- let dimensions = self.get_dimensions(dpi, size_callback)?;
+ let dimensions = self.get_dimensions(dpi, size_callback, is_testing)?;
if dimensions.width == 0 || dimensions.height == 0 {
return empty_pixbuf();
@@ -497,7 +399,7 @@ impl Handle {
{
let cr = cairo::Context::new(&surface);
- self.render_cairo_sub(&cr, id, dpi, size_callback)?;
+ self.render_cairo_sub(&cr, id, dpi, size_callback, is_testing)?;
}
let surface = SharedImageSurface::new(surface, SurfaceType::SRgb)?;
@@ -508,10 +410,6 @@ impl Handle {
pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
self.get_svg().get_intrinsic_dimensions()
}
-
- pub fn set_testing(&self, testing: bool) {
- self.is_testing.set(testing);
- }
}
fn check_cairo_context(cr: &cairo::Context) -> Result<(), RenderingError> {
diff --git a/rsvg_internals/src/pixbuf_utils.rs b/rsvg_internals/src/pixbuf_utils.rs
index bb4a58b4..1a5995cd 100644
--- a/rsvg_internals/src/pixbuf_utils.rs
+++ b/rsvg_internals/src/pixbuf_utils.rs
@@ -178,7 +178,7 @@ fn render_to_pixbuf_at_size(
f64::from(width) / f64::from(dimensions.width),
f64::from(height) / f64::from(dimensions.height),
);
- handle.render_cairo_sub(&cr, None, dpi, &SizeCallback::default())?;
+ handle.render_cairo_sub(&cr, None, dpi, &SizeCallback::default(), false)?;
}
let shared_surface = SharedImageSurface::new(surface, SurfaceType::SRgb)?;
@@ -225,25 +225,21 @@ fn pixbuf_from_file_with_size_mode(
let load_options = LoadOptions::new(LoadFlags::default(), Some(base_url));
- let handle = Handle::new();
let cancellable: Option<&gio::Cancellable> = None;
- if let Err(e) = file
+ let handle = match file
.read(cancellable)
.map_err(|e| LoadingError::from(e))
- .and_then(|stream| {
- handle.read_stream_sync(
- &load_options,
- &stream.upcast(),
- None,
- )
- })
+ .and_then(|stream| Handle::from_stream(&load_options, &stream.upcast(), None))
{
- set_gerror(error, 0, &format!("{}", e));
- return ptr::null_mut();
- }
+ Ok(handle) => handle,
+ Err(e) => {
+ set_gerror(error, 0, &format!("{}", e));
+ return ptr::null_mut();
+ }
+ };
handle
- .get_dimensions(dpi, &SizeCallback::default())
+ .get_dimensions(dpi, &SizeCallback::default(), false)
.and_then(|dimensions| {
let (width, height) = get_final_size(&dimensions, size_mode);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]