Compare commits

...

10 Commits

Author SHA1 Message Date
Michael Pfaff 5fa9e8f883 Adjust C APIs to improve performance and clean-up a tiny bit 2024-06-19 00:07:55 -04:00
Michael Pfaff 4ac0bbae7e Improve canvas_text example 2024-06-18 18:18:46 -04:00
Michael Pfaff 1b070fc0db Merge remote-tracking branch 'origin/main' 2024-06-18 18:01:53 -04:00
Michael Pfaff e5912d7d70 Improve C bindings and canvas_text example 2024-06-18 18:01:18 -04:00
Philip Deuchler 4968e819c0
Remove stdarch_arm_crc32 feature as it is now stable (#566)
Fixes #565
2024-06-11 10:31:35 +00:00
Sebastian 30419d0766
Fix #553 (#555)
* use a Result for font functions that can fail

* derive Debug for FontError and add data to the variants
2024-03-10 15:08:16 +00:00
Samson dc6034f666
Replace platform-intrinsic with core_intrinsics (#559)
Co-authored-by: Sebastian <s3bk@protonmail.com>
2024-03-05 11:09:28 +00:00
John Vandenberg 91d821a1f2
fix typos (#556) 2024-03-05 10:56:30 +00:00
Jonas Pleyer f1bce9fd62
bump simd to 0.5.3 in order push fixes for stdsimd feature upstream (#557) 2024-03-05 10:49:13 +00:00
Sebastian cb4eb597c3
update pdf stuff (#552) 2024-02-14 16:32:57 +00:00
11 changed files with 1495 additions and 722 deletions

1949
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -4,11 +4,8 @@ version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"] authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018" edition = "2018"
[features]
capi = []
[lib] [lib]
crate-type = ["staticlib"] crate-type = ["staticlib", "cdylib"]
name = "pathfinder" name = "pathfinder"
[dependencies] [dependencies]
@ -16,8 +13,13 @@ font-kit = "0.6"
foreign-types = "0.3" foreign-types = "0.3"
gl = "0.14" gl = "0.14"
libc = "0.2" libc = "0.2"
simple_logger = "4.3"
usvg = "0.9" usvg = "0.9"
[dependencies.log]
version = "0.4"
features = ["max_level_info"]
[dependencies.pathfinder_canvas] [dependencies.pathfinder_canvas]
features = ["pf-text"] features = ["pf-text"]
path = "../canvas" path = "../canvas"

View File

@ -10,6 +10,7 @@
//! C bindings to Pathfinder. //! C bindings to Pathfinder.
use font_kit::font::Font;
use font_kit::handle::Handle; use font_kit::handle::Handle;
use gl; use gl;
use pathfinder_canvas::{Canvas, CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin}; use pathfinder_canvas::{Canvas, CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin};
@ -27,6 +28,7 @@ use pathfinder_gpu::Device;
use pathfinder_resources::ResourceLoader; use pathfinder_resources::ResourceLoader;
use pathfinder_resources::fs::FilesystemResourceLoader; use pathfinder_resources::fs::FilesystemResourceLoader;
use pathfinder_resources::embedded::EmbeddedResourceLoader; use pathfinder_resources::embedded::EmbeddedResourceLoader;
use pathfinder_renderer::concurrent::executor::SequentialExecutor;
use pathfinder_renderer::concurrent::rayon::RayonExecutor; use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy; use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererLevel}; use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererLevel};
@ -39,7 +41,7 @@ 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::ptr::{self, NonNull};
use std::slice; use std::slice;
use std::str; use std::str;
use usvg::{Options, Tree}; use usvg::{Options, Tree};
@ -51,6 +53,11 @@ use metal::{self, CoreAnimationDrawableRef, DeviceRef as NativeMetalDeviceRef};
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] #[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use pathfinder_metal::MetalDevice; use pathfinder_metal::MetalDevice;
#[no_mangle]
pub extern "system" fn init_logging() {
simple_logger::init_with_env().unwrap();
}
// Constants // Constants
// `canvas` // `canvas`
@ -102,6 +109,7 @@ pub type FKHandleRef = *mut Handle;
pub type PFCanvasRef = *mut CanvasRenderingContext2D; pub type PFCanvasRef = *mut CanvasRenderingContext2D;
pub type PFPathRef = *mut Path2D; pub type PFPathRef = *mut Path2D;
pub type PFCanvasFontContextRef = *mut CanvasFontContext; pub type PFCanvasFontContextRef = *mut CanvasFontContext;
pub type FKFontRef = NonNull<Font>;
pub type PFFillStyleRef = *mut FillStyle; pub type PFFillStyleRef = *mut FillStyle;
pub type PFLineCap = u8; pub type PFLineCap = u8;
pub type PFLineJoin = u8; pub type PFLineJoin = u8;
@ -272,6 +280,13 @@ pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef
Box::into_raw(Box::new(Box::from_raw(canvas).into_canvas().into_scene())) Box::into_raw(Box::new(Box::from_raw(canvas).into_canvas().into_scene()))
} }
// Extensions
#[no_mangle]
pub unsafe extern "C" fn PFCanvasClear(canvas: PFCanvasRef) {
(*canvas).clear()
}
// Drawing rectangles // Drawing rectangles
#[no_mangle] #[no_mangle]
@ -284,6 +299,11 @@ pub unsafe extern "C" fn PFCanvasStrokeRect(canvas: PFCanvasRef, rect: *const PF
(*canvas).stroke_rect((*rect).to_rust()) (*canvas).stroke_rect((*rect).to_rust())
} }
#[no_mangle]
pub unsafe extern "C" fn PFCanvasClearRect(canvas: PFCanvasRef, rect: *const PFRectF) {
(*canvas).clear_rect((*rect).to_rust())
}
// Drawing text // Drawing text
#[no_mangle] #[no_mangle]
@ -306,9 +326,8 @@ pub unsafe extern "C" fn PFCanvasStrokeText(canvas: PFCanvasRef,
pub unsafe extern "C" fn PFCanvasMeasureText(canvas: PFCanvasRef, pub unsafe extern "C" fn PFCanvasMeasureText(canvas: PFCanvasRef,
string: *const c_char, string: *const c_char,
string_len: usize, string_len: usize,
out_text_metrics: *mut PFTextMetrics) { out_text_metrics: NonNull<PFTextMetrics>) {
debug_assert!(!out_text_metrics.is_null()); out_text_metrics.write((*canvas).measure_text(to_rust_string(&string, string_len)).to_c())
*out_text_metrics = (*canvas).measure_text(to_rust_string(&string, string_len)).to_c()
} }
#[no_mangle] #[no_mangle]
@ -375,10 +394,33 @@ pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offs
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn PFCanvasSetFontByPostScriptName(canvas: PFCanvasRef, pub unsafe extern "C" fn PFCanvasFontContextGetFontByPostScriptName(context: PFCanvasFontContextRef,
postscript_name: *const c_char, postscript_name: *const c_char,
postscript_name_len: usize) { postscript_name_len: usize) -> Option<FKFontRef> {
(*canvas).set_font(to_rust_string(&postscript_name, postscript_name_len)) let name = to_rust_string(&postscript_name, postscript_name_len);
match (*context).get_font_by_postscript_name(name) {
Ok(font) => NonNull::new(Box::into_raw(Box::new(font))),
Err(e) => {
log::error!("Failed to get font {:?}: {:?}", name, e);
None
}
}
}
#[no_mangle]
pub unsafe extern "C" fn FKFontDestroy(font: FKFontRef) {
drop(Box::from_raw(font.as_ptr()))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetFont(canvas: PFCanvasRef, font: FKFontRef) -> i32 {
match (*canvas).set_font(font.as_ref().clone()) {
Ok(_) => 0,
Err(e) => {
log::error!("Failed to set font: {:?}", e);
1
}
}
} }
#[no_mangle] #[no_mangle]
@ -621,6 +663,33 @@ pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFG
(*renderer).device_mut() (*renderer).device_mut()
} }
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererSetViewport(renderer: PFGLRendererRef, new_viewport: PFRectI) -> i32 {
match (*renderer).options_mut().dest {
DestFramebuffer::Default { ref mut viewport, .. } => {
*viewport = new_viewport.to_rust();
0
}
DestFramebuffer::Other(_) => 1,
}
}
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererSetWindowSize(renderer: PFGLRendererRef, new_window_size: PFVector2I) -> i32 {
match (*renderer).options_mut().dest {
DestFramebuffer::Default { ref mut window_size, .. } => {
*window_size = new_window_size.to_rust();
0
}
DestFramebuffer::Other(_) => 1,
}
}
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererDestFramebufferSizeChanged(renderer: PFGLRendererRef) {
(*renderer).dest_framebuffer_size_changed()
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))] #[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn PFMetalDestFramebufferCreateFullWindow(window_size: *const PFVector2I) pub unsafe extern "C" fn PFMetalDestFramebufferCreateFullWindow(window_size: *const PFVector2I)
@ -785,12 +854,18 @@ pub unsafe extern "C" fn PFSceneDestroy(scene: PFSceneRef) {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn PFSceneProxyCreateFromSceneAndRayonExecutor(scene: PFSceneRef, pub unsafe extern "C" fn PFSceneProxyCreateWithSequentialExecutor(level: PFRendererLevel) -> PFSceneProxyRef {
level: PFRendererLevel) Box::into_raw(Box::new(SceneProxy::new(to_rust_renderer_level(level), SequentialExecutor)))
-> PFSceneProxyRef { }
Box::into_raw(Box::new(SceneProxy::from_scene(*Box::from_raw(scene),
to_rust_renderer_level(level), #[no_mangle]
RayonExecutor))) pub unsafe extern "C" fn PFSceneProxyCreateWithRayonExecutor(level: PFRendererLevel) -> PFSceneProxyRef {
Box::into_raw(Box::new(SceneProxy::new(to_rust_renderer_level(level), RayonExecutor)))
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyReplaceScene(scene_proxy: PFSceneProxyRef, scene: PFSceneRef) {
(*scene_proxy).replace_scene(*Box::from_raw(scene))
} }
#[no_mangle] #[no_mangle]

View File

@ -10,6 +10,7 @@
use crate::{CanvasRenderingContext2D, State, TextAlign, TextBaseline}; use crate::{CanvasRenderingContext2D, State, TextAlign, TextBaseline};
use font_kit::canvas::RasterizationOptions; use font_kit::canvas::RasterizationOptions;
use font_kit::error::{FontLoadingError, SelectionError};
use font_kit::family_name::FamilyName; use font_kit::family_name::FamilyName;
use font_kit::handle::Handle; use font_kit::handle::Handle;
use font_kit::hinting::HintingOptions; use font_kit::hinting::HintingOptions;
@ -103,9 +104,10 @@ impl CanvasRenderingContext2D {
} }
#[inline] #[inline]
pub fn set_font<FC>(&mut self, font_collection: FC) where FC: IntoFontCollection { pub fn set_font<FC>(&mut self, font_collection: FC) -> Result<(), FontError> where FC: IntoFontCollection {
let font_collection = font_collection.into_font_collection(&self.canvas_font_context); let font_collection = font_collection.into_font_collection(&self.canvas_font_context)?;
self.current_state.font_collection = font_collection; self.current_state.font_collection = font_collection;
Ok(())
} }
#[inline] #[inline]
@ -152,13 +154,7 @@ pub trait ToTextLayout {
impl ToTextLayout for str { impl ToTextLayout for str {
fn layout(&self, state: CanvasState) -> Cow<TextMetrics> { fn layout(&self, state: CanvasState) -> Cow<TextMetrics> {
let skribo_layout = Rc::new(skribo::layout(&TextStyle { size: state.0.font_size }, Cow::Owned(TextMetrics::layout(self, &state.0.font_collection, state.0.font_size, state.0.text_align, state.0.text_baseline))
&state.0.font_collection,
self));
Cow::Owned(TextMetrics::new(skribo_layout,
state.0.font_size,
state.0.text_align,
state.0.text_baseline))
} }
} }
@ -188,6 +184,13 @@ impl ToTextLayout for TextMetrics {
#[derive(Clone)] #[derive(Clone)]
pub struct CanvasFontContext(pub(crate) Rc<RefCell<CanvasFontContextData>>); pub struct CanvasFontContext(pub(crate) Rc<RefCell<CanvasFontContextData>>);
/// The reason a font could not be loaded
#[derive(Debug)]
pub enum FontError {
NotFound(SelectionError),
LoadError(FontLoadingError),
}
pub(super) struct CanvasFontContextData { pub(super) struct CanvasFontContextData {
pub(super) font_context: FontContext<Font>, pub(super) font_context: FontContext<Font>,
#[allow(dead_code)] #[allow(dead_code)]
@ -224,16 +227,15 @@ impl CanvasFontContext {
CanvasFontContext::new(Arc::new(MemSource::from_fonts(fonts).unwrap())) CanvasFontContext::new(Arc::new(MemSource::from_fonts(fonts).unwrap()))
} }
fn get_font_by_postscript_name(&self, postscript_name: &str) -> Font { pub fn get_font_by_postscript_name(&self, postscript_name: &str) -> Result<Font, FontError> {
let this = self.0.borrow(); let this = self.0.borrow();
if let Some(cached_font) = this.font_context.get_cached_font(postscript_name) { if let Some(cached_font) = this.font_context.get_cached_font(postscript_name) {
return (*cached_font).clone(); return Ok((*cached_font).clone());
} }
this.font_source this.font_source
.select_by_postscript_name(postscript_name) .select_by_postscript_name(postscript_name)
.expect("Couldn't find a font with that PostScript name!") .map_err(FontError::NotFound)?
.load() .load().map_err(FontError::LoadError)
.expect("Failed to load the font!")
} }
} }
@ -314,6 +316,13 @@ impl TextMetrics {
} }
} }
pub fn layout(string: &str, font_collection: &FontCollection, font_size: f32, text_align: TextAlign, text_baseline: TextBaseline) -> TextMetrics {
let skribo_layout = Rc::new(skribo::layout(&TextStyle { size: font_size },
font_collection,
string));
TextMetrics::new(skribo_layout, font_size, text_align, text_baseline)
}
pub fn text_x_offset(&self) -> f32 { pub fn text_x_offset(&self) -> f32 {
if self.text_x_offset.get().is_none() { if self.text_x_offset.get().is_none() {
self.text_x_offset.set(Some(match self.align { self.text_x_offset.set(Some(match self.align {
@ -523,46 +532,46 @@ impl VerticalMetrics {
/// Various things that can be conveniently converted into font collections for use with /// Various things that can be conveniently converted into font collections for use with
/// `CanvasRenderingContext2D::set_font()`. /// `CanvasRenderingContext2D::set_font()`.
pub trait IntoFontCollection { pub trait IntoFontCollection {
fn into_font_collection(self, font_context: &CanvasFontContext) -> Arc<FontCollection>; fn into_font_collection(self, font_context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError>;
} }
impl IntoFontCollection for Arc<FontCollection> { impl IntoFontCollection for Arc<FontCollection> {
#[inline] #[inline]
fn into_font_collection(self, _: &CanvasFontContext) -> Arc<FontCollection> { fn into_font_collection(self, _: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
self Ok(self)
} }
} }
impl IntoFontCollection for FontFamily { impl IntoFontCollection for FontFamily {
#[inline] #[inline]
fn into_font_collection(self, _: &CanvasFontContext) -> Arc<FontCollection> { fn into_font_collection(self, _: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
let mut font_collection = FontCollection::new(); let mut font_collection = FontCollection::new();
font_collection.add_family(self); font_collection.add_family(self);
Arc::new(font_collection) Ok(Arc::new(font_collection))
} }
} }
impl IntoFontCollection for Vec<FontFamily> { impl IntoFontCollection for Vec<FontFamily> {
#[inline] #[inline]
fn into_font_collection(self, _: &CanvasFontContext) -> Arc<FontCollection> { fn into_font_collection(self, _: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
let mut font_collection = FontCollection::new(); let mut font_collection = FontCollection::new();
for family in self { for family in self {
font_collection.add_family(family); font_collection.add_family(family);
} }
Arc::new(font_collection) Ok(Arc::new(font_collection))
} }
} }
impl IntoFontCollection for Font { impl IntoFontCollection for Font {
#[inline] #[inline]
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> { fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
FontFamily::new_from_font(self).into_font_collection(context) Ok(FontFamily::new_from_font(self).into_font_collection(context)?)
} }
} }
impl<'a> IntoFontCollection for &'a [Font] { impl<'a> IntoFontCollection for &'a [Font] {
#[inline] #[inline]
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> { fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
let mut family = FontFamily::new(); let mut family = FontFamily::new();
for font in self { for font in self {
family.add_font(FontRef::new((*font).clone())) family.add_font(FontRef::new((*font).clone()))
@ -573,19 +582,19 @@ impl<'a> IntoFontCollection for &'a [Font] {
impl<'a> IntoFontCollection for &'a str { impl<'a> IntoFontCollection for &'a str {
#[inline] #[inline]
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> { fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
context.get_font_by_postscript_name(self).into_font_collection(context) context.get_font_by_postscript_name(self)?.into_font_collection(context)
} }
} }
impl<'a, 'b> IntoFontCollection for &'a [&'b str] { impl<'a, 'b> IntoFontCollection for &'a [&'b str] {
#[inline] #[inline]
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> { fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
let mut font_collection = FontCollection::new(); let mut font_collection = FontCollection::new();
for postscript_name in self { for postscript_name in self {
let font = context.get_font_by_postscript_name(postscript_name); let font = context.get_font_by_postscript_name(postscript_name)?;
font_collection.add_family(FontFamily::new_from_font(font)); font_collection.add_family(FontFamily::new_from_font(font));
} }
Arc::new(font_collection) Ok(Arc::new(font_collection))
} }
} }

View File

@ -367,14 +367,14 @@ impl Contour {
return Contour::from_rect(rect); return Contour::from_rect(rect);
} }
let radius = radius.min(rect.size() * 0.5); let radius = radius.min(rect.size() * 0.5);
let contol_point_offset = radius * QUARTER_ARC_CP_FROM_OUTSIDE; let control_point_offset = radius * QUARTER_ARC_CP_FROM_OUTSIDE;
let mut contour = Contour::with_capacity(8); let mut contour = Contour::with_capacity(8);
// upper left corner // upper left corner
{ {
let p0 = rect.origin(); let p0 = rect.origin();
let p1 = p0 + contol_point_offset; let p1 = p0 + control_point_offset;
let p2 = p0 + radius; let p2 = p0 + radius;
contour.push_endpoint(vec2f(p0.x(), p2.y())); contour.push_endpoint(vec2f(p0.x(), p2.y()));
contour.push_cubic( contour.push_cubic(
@ -387,7 +387,7 @@ impl Contour {
// upper right // upper right
{ {
let p0 = rect.upper_right(); let p0 = rect.upper_right();
let p1 = p0 + contol_point_offset * vec2f(-1.0, 1.0); let p1 = p0 + control_point_offset * vec2f(-1.0, 1.0);
let p2 = p0 + radius * vec2f(-1.0, 1.0); let p2 = p0 + radius * vec2f(-1.0, 1.0);
contour.push_endpoint(vec2f(p2.x(), p0.y())); contour.push_endpoint(vec2f(p2.x(), p0.y()));
contour.push_cubic( contour.push_cubic(
@ -400,7 +400,7 @@ impl Contour {
// lower right // lower right
{ {
let p0 = rect.lower_right(); let p0 = rect.lower_right();
let p1 = p0 + contol_point_offset * vec2f(-1.0, -1.0); let p1 = p0 + control_point_offset * vec2f(-1.0, -1.0);
let p2 = p0 + radius * vec2f(-1.0, -1.0); let p2 = p0 + radius * vec2f(-1.0, -1.0);
contour.push_endpoint(vec2f(p0.x(), p2.y())); contour.push_endpoint(vec2f(p0.x(), p2.y()));
contour.push_cubic( contour.push_cubic(
@ -413,7 +413,7 @@ impl Contour {
// lower left // lower left
{ {
let p0 = rect.lower_left(); let p0 = rect.lower_left();
let p1 = p0 + contol_point_offset * vec2f(1.0, -1.0); let p1 = p0 + control_point_offset * vec2f(1.0, -1.0);
let p2 = p0 + radius * vec2f(1.0, -1.0); let p2 = p0 + radius * vec2f(1.0, -1.0);
contour.push_endpoint(vec2f(p2.x(), p0.y())); contour.push_endpoint(vec2f(p2.x(), p0.y()));
contour.push_cubic( contour.push_cubic(

View File

@ -50,8 +50,8 @@ use std::path::PathBuf;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use usvg::{Options as UsvgOptions, Tree as SvgTree}; use usvg::{Options as UsvgOptions, Tree as SvgTree};
use pdf::file::File as PdfFile; use pdf::file::{CachedFile, FileOptions};
use pdf_render::Cache as PdfRenderCache; use pdf_render::{Cache as PdfRenderCache, SceneBackend};
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))] #[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
use pathfinder_gl::GLDevice as DeviceImpl; use pathfinder_gl::GLDevice as DeviceImpl;
@ -86,7 +86,7 @@ mod ui;
enum Content { enum Content {
Svg(SvgTree), Svg(SvgTree),
Pdf { Pdf {
file: PdfFile<Vec<u8>>, file: CachedFile<Vec<u8>>,
cache: PdfRenderCache, cache: PdfRenderCache,
page_nr: u32 page_nr: u32
} }
@ -773,8 +773,9 @@ impl Content {
} }
Content::Pdf { ref file, ref mut cache, page_nr } => { Content::Pdf { ref file, ref mut cache, page_nr } => {
let page = file.get_page(page_nr).expect("no such page"); let page = file.get_page(page_nr).expect("no such page");
let (scene, _) = cache.render_page(file, &page, Transform2F::default()).unwrap(); let mut backend = SceneBackend::new(cache);
(scene, String::new()) pdf_render::render_page(&mut backend, &file.resolver(), &page, Transform2F::default()).unwrap();
(backend.finish(), String::new())
} }
} }
} }
@ -791,7 +792,7 @@ fn load_scene(resource_loader: &dyn ResourceLoader,
if let Ok(tree) = SvgTree::from_data(&data, &UsvgOptions::default()) { if let Ok(tree) = SvgTree::from_data(&data, &UsvgOptions::default()) {
Content::Svg(tree) Content::Svg(tree)
} else if let Ok(file) = PdfFile::from_data(data) { } else if let Ok(file) = FileOptions::cached().load(data) {
Content::Pdf { file, cache: PdfRenderCache::new(), page_nr: 0 } Content::Pdf { file, cache: PdfRenderCache::new(), page_nr: 0 }
} else { } else {
panic!("can't load data"); panic!("can't load data");

View File

@ -25,6 +25,7 @@ use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile; use sdl2::video::GLProfile;
use std::iter; use std::iter;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant};
fn main() { fn main() {
// Set up SDL2. // Set up SDL2.
@ -34,7 +35,10 @@ fn main() {
// Make sure we have at least a GL 3.0 context. Pathfinder requires this. // Make sure we have at least a GL 3.0 context. Pathfinder requires this.
let gl_attributes = video.gl_attr(); let gl_attributes = video.gl_attr();
gl_attributes.set_context_profile(GLProfile::Core); gl_attributes.set_context_profile(GLProfile::Core);
gl_attributes.set_context_version(3, 3); gl_attributes.set_context_version(4, 1);
gl_attributes.set_context_flags()
.forward_compatible()
.set();
// Open a window. // Open a window.
let window_size = vec2i(640, 480); let window_size = vec2i(640, 480);
@ -66,17 +70,32 @@ fn main() {
// Wait for a keypress. // Wait for a keypress.
let mut event_pump = sdl_context.event_pump().unwrap(); let mut event_pump = sdl_context.event_pump().unwrap();
let mut n = 0;
let mut last_update = Instant::now();
let mut fps_buf = String::new();
loop { loop {
match event_pump.wait_event() { match event_pump.poll_event() {
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return, Some(Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. }) => return,
Event::Window { win_event: WindowEvent::Exposed, .. } => { Some(Event::Window { win_event: WindowEvent::Exposed, .. }) | None => {
// Make a canvas. // Make a canvas.
let mut canvas = Canvas::new(window_size.to_f32()).get_context_2d(font_context.clone()); let mut canvas = Canvas::new(window_size.to_f32()).get_context_2d(font_context.clone());
// Draw the text. // Draw the text.
canvas.set_font("Overpass-Regular"); canvas.set_font("Overpass-Regular").unwrap();
canvas.set_font_size(32.0); canvas.set_font_size(32.0);
let now = Instant::now();
let elapsed = now.duration_since(last_update);
if elapsed >= Duration::from_millis(50) {
last_update = now;
let fps = (n as f64) * ((Duration::from_secs(1).as_micros() as f64) / (elapsed.as_micros() as f64));
fps_buf.clear();
fps_buf.push_str("FPS: ");
use std::fmt::Write;
write!(fps_buf, "{fps:.2}").unwrap();
n = 0;
}
canvas.fill_text("Hello Pathfinder!", vec2f(32.0, 48.0)); canvas.fill_text("Hello Pathfinder!", vec2f(32.0, 48.0));
canvas.fill_text(&fps_buf, vec2f(32.0, 96.0));
canvas.set_text_align(TextAlign::Right); canvas.set_text_align(TextAlign::Right);
canvas.stroke_text("Goodbye Pathfinder!", vec2f(608.0, 464.0)); canvas.stroke_text("Goodbye Pathfinder!", vec2f(608.0, 464.0));
@ -86,6 +105,8 @@ fn main() {
RayonExecutor); RayonExecutor);
scene.build_and_render(&mut renderer, BuildOptions::default()); scene.build_and_render(&mut renderer, BuildOptions::default());
window.gl_swap_window(); window.gl_swap_window();
n += 1;
}, },
_ => {} _ => {}
} }

View File

@ -31,5 +31,5 @@ export SPIRVCROSS=spirv-cross.exe
Note: the Windows versions of `glslangValidator` and `spirv-cross` may change Note: the Windows versions of `glslangValidator` and `spirv-cross` may change
the line endings of the generated output. Please take care to ensure that the line endings of the generated output. Please take care to ensure that
unintended line ending changes aren't accidentally commited, for instance by unintended line ending changes aren't accidentally committed, for instance by
[configuring Git to automatically handle line endings](https://docs.github.com/en/github/using-git/configuring-git-to-handle-line-endings#global-settings-for-line-endings). [configuring Git to automatically handle line endings](https://docs.github.com/en/github/using-git/configuring-git-to-handle-line-endings#global-settings-for-line-endings).

View File

@ -1,6 +1,6 @@
[package] [package]
name = "pathfinder_simd" name = "pathfinder_simd"
version = "0.5.2" version = "0.5.3"
edition = "2018" edition = "2018"
authors = ["Patrick Walton <pcwalton@mimiga.net>"] authors = ["Patrick Walton <pcwalton@mimiga.net>"]
build = "build.rs" build = "build.rs"

View File

@ -10,6 +10,7 @@
use std::arch::aarch64::{self, float32x2_t, float32x4_t, int32x2_t, int32x4_t}; use std::arch::aarch64::{self, float32x2_t, float32x4_t, int32x2_t, int32x4_t};
use std::arch::aarch64::{uint32x2_t, uint32x4_t}; use std::arch::aarch64::{uint32x2_t, uint32x4_t};
use std::intrinsics::simd::*;
use std::f32; use std::f32;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::mem; use std::mem;
@ -869,33 +870,6 @@ impl Index<usize> for U32x4 {
} }
} }
// Intrinsics
extern "platform-intrinsic" {
fn simd_add<T>(x: T, y: T) -> T;
fn simd_div<T>(x: T, y: T) -> T;
fn simd_mul<T>(x: T, y: T) -> T;
fn simd_sub<T>(x: T, y: T) -> T;
fn simd_shr<T>(x: T, y: T) -> T;
fn simd_and<T>(x: T, y: T) -> T;
fn simd_or<T>(x: T, y: T) -> T;
fn simd_xor<T>(x: T, y: T) -> T;
fn simd_fmin<T>(x: T, y: T) -> T;
fn simd_fmax<T>(x: T, y: T) -> T;
fn simd_eq<T, U>(x: T, y: T) -> U;
fn simd_gt<T, U>(x: T, y: T) -> U;
fn simd_le<T, U>(x: T, y: T) -> U;
fn simd_lt<T, U>(x: T, y: T) -> U;
fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
fn simd_cast<T, U>(x: T) -> U;
}
extern "C" { extern "C" {
#[link_name = "llvm.fabs.v2f32"] #[link_name = "llvm.fabs.v2f32"]
fn fabs_v2f32(a: float32x2_t) -> float32x2_t; fn fabs_v2f32(a: float32x2_t) -> float32x2_t;

View File

@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![cfg_attr(pf_rustc_nightly, feature(link_llvm_intrinsics, platform_intrinsics))] #![cfg_attr(pf_rustc_nightly, allow(internal_features))]
#![cfg_attr(all(target_arch = "aarch64", pf_rustc_nightly), feature(stdarch_arm_crc32))] #![cfg_attr(pf_rustc_nightly, feature(link_llvm_intrinsics, core_intrinsics))]
#![cfg_attr(pf_rustc_nightly, feature(simd_ffi))] #![cfg_attr(pf_rustc_nightly, feature(simd_ffi))]
//! A minimal SIMD abstraction, usable outside of Pathfinder. //! A minimal SIMD abstraction, usable outside of Pathfinder.