Auto merge of #365 - pcwalton:c-svg, r=pcwalton

Expose `pathfinder_svg` to the C API

Closes #357.
This commit is contained in:
bors-servo 2020-06-24 20:36:08 -04:00 committed by GitHub
commit 265e781efa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 65 additions and 19 deletions

2
Cargo.lock generated
View File

@ -1698,6 +1698,8 @@ dependencies = [
"pathfinder_renderer 0.5.0", "pathfinder_renderer 0.5.0",
"pathfinder_resources 0.5.0", "pathfinder_resources 0.5.0",
"pathfinder_simd 0.5.0", "pathfinder_simd 0.5.0",
"pathfinder_svg 0.5.0",
"usvg 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]

View File

@ -12,6 +12,7 @@ font-kit = "0.6"
foreign-types = "0.3" foreign-types = "0.3"
gl = "0.14" gl = "0.14"
libc = "0.2" libc = "0.2"
usvg = "0.9"
[dependencies.pathfinder_canvas] [dependencies.pathfinder_canvas]
features = ["pf-text"] features = ["pf-text"]
@ -41,6 +42,9 @@ path = "../resources"
[dependencies.pathfinder_simd] [dependencies.pathfinder_simd]
path = "../simd" path = "../simd"
[dependencies.pathfinder_svg]
path = "../svg"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
metal = "0.17" metal = "0.17"

View File

@ -34,11 +34,14 @@ use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::options::{BuildOptions, RenderTransform}; use pathfinder_renderer::options::{BuildOptions, RenderTransform};
use pathfinder_renderer::scene::Scene; use pathfinder_renderer::scene::Scene;
use pathfinder_simd::default::F32x4; use pathfinder_simd::default::F32x4;
use pathfinder_svg::SVGScene;
use std::ffi::CString; use std::ffi::CString;
use std::os::raw::{c_char, c_void}; use std::os::raw::{c_char, c_void};
use std::path::PathBuf; use std::path::PathBuf;
use std::ptr;
use std::slice; use std::slice;
use std::str; use std::str;
use usvg::{Options, Tree};
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] #[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use metal::{self, CAMetalLayer, CoreAnimationLayerRef}; use metal::{self, CAMetalLayer, CoreAnimationLayerRef};
@ -204,6 +207,9 @@ pub type PFBuildOptionsRef = *mut BuildOptions;
pub type PFRenderTransformRef = *mut RenderTransform; pub type PFRenderTransformRef = *mut RenderTransform;
pub type PFRendererLevel = u8; pub type PFRendererLevel = u8;
// `svg`
pub type PFSVGSceneRef = *mut SVGScene;
// `canvas` // `canvas`
/// This function internally adds a reference to the font context. Therefore, if you created the /// This function internally adds a reference to the font context. Therefore, if you created the
@ -735,6 +741,40 @@ pub unsafe extern "C" fn PFSceneProxyDestroy(scene_proxy: PFSceneProxyRef) {
drop(Box::from_raw(scene_proxy)) drop(Box::from_raw(scene_proxy))
} }
// `svg`
/// Returns `NULL` on failure.
#[no_mangle]
pub unsafe extern "C" fn PFSVGSceneCreateWithMemory(bytes: *const c_char, byte_len: usize)
-> PFSVGSceneRef {
let data = slice::from_raw_parts(bytes as *const _, byte_len);
let tree = match Tree::from_data(data, &Options::default()) {
Ok(tree) => tree,
Err(_) => return ptr::null_mut(),
};
let svg_scene = SVGScene::from_tree(&tree);
Box::into_raw(Box::new(svg_scene))
}
/// Returns `NULL` on failure.
#[no_mangle]
pub unsafe extern "C" fn PFSVGSceneCreateWithPath(path: *const c_char) -> PFSVGSceneRef {
let string = to_rust_string(&path, 0);
let path = PathBuf::from(string);
let tree = match Tree::from_file(path, &Options::default()) {
Ok(tree) => tree,
Err(_) => return ptr::null_mut(),
};
let svg_scene = SVGScene::from_tree(&tree);
Box::into_raw(Box::new(svg_scene))
}
/// Destroys the SVG and returns the scene.
#[no_mangle]
pub unsafe extern "C" fn PFSVGSceneIntoScene(svg: PFSVGSceneRef) -> PFSceneRef {
Box::into_raw(Box::new((*Box::from_raw(svg)).scene))
}
// Helpers for `canvas` // Helpers for `canvas`
unsafe fn to_rust_string(ptr: &*const c_char, mut len: usize) -> &str { unsafe fn to_rust_string(ptr: &*const c_char, mut len: usize) -> &str {

View File

@ -42,7 +42,7 @@ use pathfinder_renderer::options::{BuildOptions, RenderTransform};
use pathfinder_renderer::paint::Paint; use pathfinder_renderer::paint::Paint;
use pathfinder_renderer::scene::{DrawPath, RenderTarget, Scene}; use pathfinder_renderer::scene::{DrawPath, RenderTarget, Scene};
use pathfinder_resources::ResourceLoader; use pathfinder_resources::ResourceLoader;
use pathfinder_svg::BuiltSVG; use pathfinder_svg::SVGScene;
use pathfinder_ui::{MousePosition, UIEvent}; use pathfinder_ui::{MousePosition, UIEvent};
use std::fs::File; use std::fs::File;
use std::io::{BufWriter, Read}; use std::io::{BufWriter, Read};
@ -759,7 +759,7 @@ fn load_scene(resource_loader: &dyn ResourceLoader,
input_path: &SVGPath, input_path: &SVGPath,
viewport_size: Vector2I, viewport_size: Vector2I,
filter: Option<PatternFilter>) filter: Option<PatternFilter>)
-> (BuiltSVG, Tree) { -> (SVGScene, Tree) {
let mut data; let mut data;
match *input_path { match *input_path {
SVGPath::Default => data = resource_loader.slurp(DEFAULT_SVG_VIRTUAL_PATH).unwrap(), SVGPath::Default => data = resource_loader.slurp(DEFAULT_SVG_VIRTUAL_PATH).unwrap(),
@ -778,7 +778,7 @@ fn load_scene(resource_loader: &dyn ResourceLoader,
// FIXME(pcwalton): Rework how transforms work in the demo. The transform affects the final // FIXME(pcwalton): Rework how transforms work in the demo. The transform affects the final
// composite steps, breaking this approach. // composite steps, breaking this approach.
fn build_svg_tree(tree: &Tree, viewport_size: Vector2I, filter: Option<PatternFilter>) fn build_svg_tree(tree: &Tree, viewport_size: Vector2I, filter: Option<PatternFilter>)
-> BuiltSVG { -> SVGScene {
let mut scene = Scene::new(); let mut scene = Scene::new();
let filter_info = filter.map(|filter| { let filter_info = filter.map(|filter| {
let scale = match filter { let scale = match filter {
@ -792,7 +792,7 @@ fn build_svg_tree(tree: &Tree, viewport_size: Vector2I, filter: Option<PatternFi
FilterInfo { filter, render_target_id, render_target_size } FilterInfo { filter, render_target_id, render_target_size }
}); });
let mut built_svg = BuiltSVG::from_tree_and_scene(&tree, scene); let mut built_svg = SVGScene::from_tree_and_scene(&tree, scene);
if let Some(FilterInfo { filter, render_target_id, render_target_size }) = filter_info { if let Some(FilterInfo { filter, render_target_id, render_target_size }) = filter_info {
let mut pattern = Pattern::from_render_target(render_target_id, render_target_size); let mut pattern = Pattern::from_render_target(render_target_id, render_target_size);
pattern.set_filter(Some(filter)); pattern.set_filter(Some(filter));
@ -818,7 +818,7 @@ fn center_of_window(window_size: &WindowSize) -> Vector2F {
window_size.device_size().to_f32() * 0.5 window_size.device_size().to_f32() * 0.5
} }
fn get_svg_building_message(built_svg: &BuiltSVG) -> String { fn get_svg_building_message(built_svg: &SVGScene) -> String {
if built_svg.result_flags.is_empty() { if built_svg.result_flags.is_empty() {
return String::new(); return String::new();
} }

View File

@ -24,7 +24,7 @@ use pathfinder_geometry::transform3d::Transform4F32;
use pathfinder_geometry::transform3d::Perspective; use pathfinder_geometry::transform3d::Perspective;
use pathfinder_gpu::Device; use pathfinder_gpu::Device;
use pathfinder_simd::default::F32x4; use pathfinder_simd::default::F32x4;
use pathfinder_svg::BuiltSVG; use pathfinder_svg::SVGScene;
use pathfinder_renderer::scene::Scene; use pathfinder_renderer::scene::Scene;
use pathfinder_renderer::builder::RenderTransform; use pathfinder_renderer::builder::RenderTransform;
@ -58,7 +58,7 @@ impl<D: Display> ImmersiveDemo<D> {
let options = Options::get(); let options = Options::get();
let svg_data = resources.slurp(DEFAULT_SVG_VIRTUAL_PATH)?; let svg_data = resources.slurp(DEFAULT_SVG_VIRTUAL_PATH)?;
let tree = usvg::Tree::from_data(&svg_data[..], &usvg::Options::default())?; let tree = usvg::Tree::from_data(&svg_data[..], &usvg::Options::default())?;
let svg = BuiltSVG::from_tree(tree); let svg = SVGScene::from_tree(tree);
let svg_size = svg.scene.view_box.size(); let svg_size = svg.scene.view_box.size();
let scene_thread_proxy = SceneThreadProxy::new(svg.scene, options); let scene_thread_proxy = SceneThreadProxy::new(svg.scene, options);
let _ = scene_thread_proxy.sender.send(MainToSceneMsg::SetDrawableSize(display.size())); let _ = scene_thread_proxy.sender.send(MainToSceneMsg::SetDrawableSize(display.size()));

View File

@ -48,7 +48,7 @@ use pathfinder_renderer::options::RenderTransform;
use pathfinder_resources::ResourceLoader; use pathfinder_resources::ResourceLoader;
use pathfinder_resources::fs::FilesystemResourceLoader; use pathfinder_resources::fs::FilesystemResourceLoader;
use pathfinder_simd::default::F32x4; use pathfinder_simd::default::F32x4;
use pathfinder_svg::BuiltSVG; use pathfinder_svg::SVGScene;
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::CStr; use std::ffi::CStr;
@ -135,7 +135,7 @@ pub unsafe extern "C" fn magicleap_pathfinder_demo_load(app: *mut c_void, svg_fi
struct MagicLeapPathfinder { struct MagicLeapPathfinder {
renderers: HashMap<(EGLSurface, EGLDisplay), Renderer<GLDevice>>, renderers: HashMap<(EGLSurface, EGLDisplay), Renderer<GLDevice>>,
svgs: HashMap<String, BuiltSVG>, svgs: HashMap<String, SVGScene>,
resources: FilesystemResourceLoader, resources: FilesystemResourceLoader,
} }
@ -185,7 +185,7 @@ pub unsafe extern "C" fn magicleap_pathfinder_render(pf: *mut c_void, options: *
let svg_filename = CStr::from_ptr(options.svg_filename).to_string_lossy(); let svg_filename = CStr::from_ptr(options.svg_filename).to_string_lossy();
let data = resources.slurp(&*svg_filename).unwrap(); let data = resources.slurp(&*svg_filename).unwrap();
let tree = Tree::from_data(&data, &UsvgOptions::default()).unwrap(); let tree = Tree::from_data(&data, &UsvgOptions::default()).unwrap();
BuiltSVG::from_tree(tree) SVGScene::from_tree(tree)
}); });
let mut width = 0; let mut width = 0;

View File

@ -37,7 +37,7 @@ use usvg::{Transform as UsvgTransform, Tree, Visibility};
const HAIRLINE_STROKE_WIDTH: f32 = 0.0333; const HAIRLINE_STROKE_WIDTH: f32 = 0.0333;
pub struct BuiltSVG { pub struct SVGScene {
pub scene: Scene, pub scene: Scene,
pub result_flags: BuildResultFlags, pub result_flags: BuildResultFlags,
pub clip_paths: HashMap<String, ClipPathId>, pub clip_paths: HashMap<String, ClipPathId>,
@ -60,18 +60,18 @@ bitflags! {
} }
} }
impl BuiltSVG { impl SVGScene {
// TODO(pcwalton): Allow a global transform to be set. // TODO(pcwalton): Allow a global transform to be set.
#[inline] #[inline]
pub fn from_tree(tree: &Tree) -> BuiltSVG { pub fn from_tree(tree: &Tree) -> SVGScene {
BuiltSVG::from_tree_and_scene(tree, Scene::new()) SVGScene::from_tree_and_scene(tree, Scene::new())
} }
// TODO(pcwalton): Allow a global transform to be set. // TODO(pcwalton): Allow a global transform to be set.
pub fn from_tree_and_scene(tree: &Tree, scene: Scene) -> BuiltSVG { pub fn from_tree_and_scene(tree: &Tree, scene: Scene) -> SVGScene {
// TODO(pcwalton): Maybe have a `SVGBuilder` type to hold the clip path IDs and other // TODO(pcwalton): Maybe have a `SVGBuilder` type to hold the clip path IDs and other
// transient data separate from `BuiltSVG`? // transient data separate from `SVGScene`?
let mut built_svg = BuiltSVG { let mut built_svg = SVGScene {
scene, scene,
result_flags: BuildResultFlags::empty(), result_flags: BuildResultFlags::empty(),
clip_paths: HashMap::new(), clip_paths: HashMap::new(),

View File

@ -2,7 +2,7 @@ use std::fs::File;
use std::io::{Read, BufWriter}; use std::io::{Read, BufWriter};
use std::error::Error; use std::error::Error;
use std::path::PathBuf; use std::path::PathBuf;
use pathfinder_svg::BuiltSVG; use pathfinder_svg::SVGScene;
use pathfinder_export::{Export, FileFormat}; use pathfinder_export::{Export, FileFormat};
use usvg::{Tree, Options}; use usvg::{Tree, Options};
@ -13,7 +13,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let mut data = Vec::new(); let mut data = Vec::new();
File::open(input)?.read_to_end(&mut data)?; File::open(input)?.read_to_end(&mut data)?;
let svg = BuiltSVG::from_tree(&Tree::from_data(&data, &Options::default()).unwrap()); let svg = SVGScene::from_tree(&Tree::from_data(&data, &Options::default()).unwrap());
let scene = &svg.scene; let scene = &svg.scene;
let mut writer = BufWriter::new(File::create(&output)?); let mut writer = BufWriter::new(File::create(&output)?);