[librsvg: 4/7] Reimplement c_api in terms of librsvg_crate
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 4/7] Reimplement c_api in terms of librsvg_crate
- Date: Wed, 28 Oct 2020 19:52:28 +0000 (UTC)
commit 4aa0f7c1ffa7accc85330833d91a8a892db1b3f3
Author: Federico Mena Quintero <federico gnome org>
Date: Wed Oct 28 10:34:16 2020 -0600
Reimplement c_api in terms of librsvg_crate
librsvg/c_api.rs | 248 +++++++++++++++++++++++-------------------------------
librsvg/sizing.rs | 8 ++
2 files changed, 112 insertions(+), 144 deletions(-)
---
diff --git a/librsvg/c_api.rs b/librsvg/c_api.rs
index 76779778..239dea5f 100644
--- a/librsvg/c_api.rs
+++ b/librsvg/c_api.rs
@@ -9,7 +9,6 @@ use std::sync::Once;
use std::{f64, i32};
use bitflags::bitflags;
-use float_cmp::approx_eq;
use gdk_pixbuf::Pixbuf;
use gio::prelude::*;
use glib::error::ErrorDomain;
@@ -30,14 +29,17 @@ use glib::types::instance_of;
use gobject_sys::{GEnumValue, GFlagsValue};
-use rsvg_internals::{
- rsvg_log, DefsLookupErrorKind, Handle, IntrinsicDimensions, Length, LoadOptions, LoadingError,
- RenderingError, RsvgLength, SharedImageSurface, SurfaceType, UrlResolver, ViewBox,
+use librsvg::{
+ CairoRenderer, DefsLookupErrorKind, IntrinsicDimensions, Loader, LoadingError, RenderingError,
+ SvgHandle,
};
+use rsvg_internals::{rsvg_log, RsvgLength, SharedImageSurface, SurfaceType};
+
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"));
@@ -155,11 +157,30 @@ enum LoadState {
// Being loaded using the legacy write()/close() API
Loading { buffer: Vec<u8> },
- ClosedOk { handle: Handle },
+ 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
@@ -187,6 +208,10 @@ impl BaseUrl {
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()
@@ -226,17 +251,6 @@ impl From<RsvgRectangle> for cairo::Rectangle {
}
}
-impl From<ViewBox> for RsvgRectangle {
- fn from(vb: ViewBox) -> RsvgRectangle {
- RsvgRectangle {
- x: vb.x0,
- y: vb.y0,
- width: vb.width(),
- height: vb.height(),
- }
- }
-}
-
/// Contains all the interior mutability for a RsvgHandle to be called
/// from the C API.
pub struct CHandle {
@@ -671,14 +685,6 @@ impl CHandle {
HandleFlags::from(inner.load_flags)
}
- fn load_options(&self) -> LoadOptions {
- let inner = self.inner.borrow();
-
- LoadOptions::new(UrlResolver::new(inner.base_url.get().map(|u| (*u).clone())))
- .with_unlimited_size(inner.load_flags.unlimited_size)
- .keep_image_data(inner.load_flags.keep_image_data)
- }
-
fn set_size_callback(
&self,
size_func: RsvgSizeFunc,
@@ -710,6 +716,7 @@ impl CHandle {
}
fn close(&self) -> Result<(), LoadingError> {
+ let inner = self.inner.borrow();
let mut state = self.load_state.borrow_mut();
match *state {
@@ -722,7 +729,8 @@ impl CHandle {
let bytes = Bytes::from(&*buffer);
let stream = gio::MemoryInputStream::new_from_bytes(&bytes);
- self.read_stream(state, &stream.upcast(), None)
+ let base_file = inner.base_url.get_gfile();
+ self.read_stream(state, &stream.upcast(), base_file.as_ref(), None)
}
// Closing is idempotent
@@ -737,9 +745,14 @@ impl CHandle {
cancellable: Option<&gio::Cancellable>,
) -> Result<(), LoadingError> {
let state = self.load_state.borrow_mut();
+ let inner = self.inner.borrow();
match *state {
- LoadState::Start => self.read_stream(state, stream, cancellable),
+ 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 \
@@ -754,22 +767,15 @@ impl CHandle {
&self,
mut load_state: RefMut<LoadState>,
stream: &gio::InputStream,
+ base_file: Option<&gio::File>,
cancellable: Option<&gio::Cancellable>,
) -> Result<(), LoadingError> {
- match Handle::from_stream(&self.load_options(), stream, cancellable) {
- Ok(handle) => {
- *load_state = LoadState::ClosedOk { handle };
- Ok(())
- }
+ let loader = self.make_loader();
- Err(e) => {
- *load_state = LoadState::ClosedError;
- Err(e)
- }
- }
+ load_state.set_from_loading_result(loader.read_stream(stream, base_file, cancellable))
}
- fn get_handle_ref(&self) -> Result<Ref<Handle>, RenderingError> {
+ fn get_handle_ref(&self) -> Result<Ref<SvgHandle>, RenderingError> {
let state = self.load_state.borrow();
match *state {
@@ -798,9 +804,25 @@ impl CHandle {
}
}
+ 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_sub(id).map_err(warn_on_invalid_id)
+ handle.has_element_with_id(id).map_err(warn_on_invalid_id)
}
fn get_dimensions_or_empty(&self) -> RsvgDimensionData {
@@ -876,55 +898,32 @@ impl CHandle {
.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
+ }
+
pub fn get_geometry_sub(
&self,
id: Option<&str>,
) -> Result<(cairo::Rectangle, cairo::Rectangle), RenderingError> {
let handle = self.get_handle_ref()?;
- let inner = self.inner.borrow();
+ let renderer = self.make_renderer(&handle);
match id {
- Some(id) => handle.get_geometry_for_layer(
- Some(id),
- &unit_rectangle(),
- inner.dpi.into(),
- inner.is_testing,
- ),
-
- None => self.legacy_document_size_in_pixels(),
- }
- }
-
- /// 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<(cairo::Rectangle, cairo::Rectangle), RenderingError> {
- let handle = self.get_handle_ref()?;
- let inner = self.inner.borrow();
-
- let size_from_intrinsic_dimensions = handle
- .get_intrinsic_size_in_pixels(inner.dpi.into())
- .or_else(|| {
- size_in_pixels_from_percentage_width_and_height(&handle.get_intrinsic_dimensions())
- });
+ Some(id) => renderer.geometry_for_layer(Some(id), &unit_rectangle()),
- if let Some((width, height)) = size_from_intrinsic_dimensions {
- let rect = cairo::Rectangle::from_size(width, height);
- Ok((rect, rect))
- } else {
- handle.get_geometry_for_layer(
- None,
- &unit_rectangle(),
- inner.dpi.into(),
- inner.is_testing,
- )
+ None => renderer.legacy_document_size_in_pixels().map(|(w, h)| {
+ let rect = cairo::Rectangle::from_size(w, h);
+ (rect, rect)
+ }),
}
}
@@ -996,8 +995,9 @@ impl CHandle {
check_cairo_context(cr)?;
let handle = self.get_handle_ref()?;
- let inner = self.inner.borrow();
- handle.render_document(cr, viewport, inner.dpi.into(), inner.is_testing)
+
+ let renderer = self.make_renderer(&handle);
+ renderer.render_document(cr, viewport)
}
fn get_geometry_for_layer(
@@ -1006,9 +1006,10 @@ impl CHandle {
viewport: &cairo::Rectangle,
) -> Result<(RsvgRectangle, RsvgRectangle), RenderingError> {
let handle = self.get_handle_ref()?;
- let inner = self.inner.borrow();
- handle
- .get_geometry_for_layer(id, viewport, inner.dpi.into(), inner.is_testing)
+ 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)
}
@@ -1022,9 +1023,11 @@ impl CHandle {
check_cairo_context(cr)?;
let handle = self.get_handle_ref()?;
- let inner = self.inner.borrow();
- handle
- .render_layer(cr, id, viewport, inner.dpi.into(), inner.is_testing)
+
+ let renderer = self.make_renderer(&handle);
+
+ renderer
+ .render_layer(cr, id, viewport)
.map_err(warn_on_invalid_id)
}
@@ -1033,9 +1036,11 @@ impl CHandle {
id: Option<&str>,
) -> Result<(RsvgRectangle, RsvgRectangle), RenderingError> {
let handle = self.get_handle_ref()?;
- let inner = self.inner.borrow();
- handle
- .get_geometry_for_element(id, inner.dpi.into(), inner.is_testing)
+
+ 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)
}
@@ -1049,22 +1054,24 @@ impl CHandle {
check_cairo_context(cr)?;
let handle = self.get_handle_ref()?;
- let inner = self.inner.borrow();
- handle
- .render_element(cr, id, element_viewport, inner.dpi.into(), inner.is_testing)
+
+ 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()?;
- Ok(handle.get_intrinsic_dimensions())
+ 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 inner = self.inner.borrow();
-
- Ok(handle.get_intrinsic_size_in_pixels(inner.dpi.into()))
+ let renderer = self.make_renderer(&handle);
+ Ok(renderer.intrinsic_size_in_pixels())
}
fn set_testing(&self, is_testing: bool) {
@@ -1073,53 +1080,6 @@ impl CHandle {
}
}
-/// 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 rsvg_internals::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,
- }
-}
-
pub fn unit_rectangle() -> cairo::Rectangle {
cairo::Rectangle::from_size(1.0, 1.0)
}
diff --git a/librsvg/sizing.rs b/librsvg/sizing.rs
index 69fff74d..1e0b996b 100644
--- a/librsvg/sizing.rs
+++ b/librsvg/sizing.rs
@@ -4,6 +4,14 @@ 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>;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]