Compare commits

..

No commits in common. "5fa9e8f88337cca2495cee71967fd4c1c10b5642" and "a29dd979c196a00756749d06c61f7bf6978c9dc7" have entirely different histories.

11 changed files with 717 additions and 1490 deletions

1939
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -10,7 +10,6 @@
//! C bindings to Pathfinder.
use font_kit::font::Font;
use font_kit::handle::Handle;
use gl;
use pathfinder_canvas::{Canvas, CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin};
@ -28,7 +27,6 @@ use pathfinder_gpu::Device;
use pathfinder_resources::ResourceLoader;
use pathfinder_resources::fs::FilesystemResourceLoader;
use pathfinder_resources::embedded::EmbeddedResourceLoader;
use pathfinder_renderer::concurrent::executor::SequentialExecutor;
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererLevel};
@ -41,7 +39,7 @@ use pathfinder_svg::SVGScene;
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
use std::path::PathBuf;
use std::ptr::{self, NonNull};
use std::ptr;
use std::slice;
use std::str;
use usvg::{Options, Tree};
@ -53,11 +51,6 @@ use metal::{self, CoreAnimationDrawableRef, DeviceRef as NativeMetalDeviceRef};
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use pathfinder_metal::MetalDevice;
#[no_mangle]
pub extern "system" fn init_logging() {
simple_logger::init_with_env().unwrap();
}
// Constants
// `canvas`
@ -109,7 +102,6 @@ pub type FKHandleRef = *mut Handle;
pub type PFCanvasRef = *mut CanvasRenderingContext2D;
pub type PFPathRef = *mut Path2D;
pub type PFCanvasFontContextRef = *mut CanvasFontContext;
pub type FKFontRef = NonNull<Font>;
pub type PFFillStyleRef = *mut FillStyle;
pub type PFLineCap = u8;
pub type PFLineJoin = u8;
@ -280,13 +272,6 @@ pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef
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
#[no_mangle]
@ -299,11 +284,6 @@ pub unsafe extern "C" fn PFCanvasStrokeRect(canvas: PFCanvasRef, rect: *const PF
(*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
#[no_mangle]
@ -326,8 +306,9 @@ pub unsafe extern "C" fn PFCanvasStrokeText(canvas: PFCanvasRef,
pub unsafe extern "C" fn PFCanvasMeasureText(canvas: PFCanvasRef,
string: *const c_char,
string_len: usize,
out_text_metrics: NonNull<PFTextMetrics>) {
out_text_metrics.write((*canvas).measure_text(to_rust_string(&string, string_len)).to_c())
out_text_metrics: *mut PFTextMetrics) {
debug_assert!(!out_text_metrics.is_null());
*out_text_metrics = (*canvas).measure_text(to_rust_string(&string, string_len)).to_c()
}
#[no_mangle]
@ -394,33 +375,10 @@ pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offs
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFontContextGetFontByPostScriptName(context: PFCanvasFontContextRef,
pub unsafe extern "C" fn PFCanvasSetFontByPostScriptName(canvas: PFCanvasRef,
postscript_name: *const c_char,
postscript_name_len: usize) -> Option<FKFontRef> {
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
}
}
postscript_name_len: usize) {
(*canvas).set_font(to_rust_string(&postscript_name, postscript_name_len))
}
#[no_mangle]
@ -663,33 +621,6 @@ pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFG
(*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")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalDestFramebufferCreateFullWindow(window_size: *const PFVector2I)
@ -854,18 +785,12 @@ pub unsafe extern "C" fn PFSceneDestroy(scene: PFSceneRef) {
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyCreateWithSequentialExecutor(level: PFRendererLevel) -> PFSceneProxyRef {
Box::into_raw(Box::new(SceneProxy::new(to_rust_renderer_level(level), SequentialExecutor)))
}
#[no_mangle]
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))
pub unsafe extern "C" fn PFSceneProxyCreateFromSceneAndRayonExecutor(scene: PFSceneRef,
level: PFRendererLevel)
-> PFSceneProxyRef {
Box::into_raw(Box::new(SceneProxy::from_scene(*Box::from_raw(scene),
to_rust_renderer_level(level),
RayonExecutor)))
}
#[no_mangle]

View File

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

View File

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

View File

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

View File

@ -25,7 +25,6 @@ use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile;
use std::iter;
use std::sync::Arc;
use std::time::{Duration, Instant};
fn main() {
// Set up SDL2.
@ -35,10 +34,7 @@ fn main() {
// Make sure we have at least a GL 3.0 context. Pathfinder requires this.
let gl_attributes = video.gl_attr();
gl_attributes.set_context_profile(GLProfile::Core);
gl_attributes.set_context_version(4, 1);
gl_attributes.set_context_flags()
.forward_compatible()
.set();
gl_attributes.set_context_version(3, 3);
// Open a window.
let window_size = vec2i(640, 480);
@ -70,32 +66,17 @@ fn main() {
// Wait for a keypress.
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 {
match event_pump.poll_event() {
Some(Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. }) => return,
Some(Event::Window { win_event: WindowEvent::Exposed, .. }) | None => {
match event_pump.wait_event() {
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return,
Event::Window { win_event: WindowEvent::Exposed, .. } => {
// Make a canvas.
let mut canvas = Canvas::new(window_size.to_f32()).get_context_2d(font_context.clone());
// Draw the text.
canvas.set_font("Overpass-Regular").unwrap();
canvas.set_font("Overpass-Regular");
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(&fps_buf, vec2f(32.0, 96.0));
canvas.set_text_align(TextAlign::Right);
canvas.stroke_text("Goodbye Pathfinder!", vec2f(608.0, 464.0));
@ -105,8 +86,6 @@ fn main() {
RayonExecutor);
scene.build_and_render(&mut renderer, BuildOptions::default());
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
the line endings of the generated output. Please take care to ensure that
unintended line ending changes aren't accidentally committed, for instance by
unintended line ending changes aren't accidentally commited, 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).

View File

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

View File

@ -10,7 +10,6 @@
use std::arch::aarch64::{self, float32x2_t, float32x4_t, int32x2_t, int32x4_t};
use std::arch::aarch64::{uint32x2_t, uint32x4_t};
use std::intrinsics::simd::*;
use std::f32;
use std::fmt::{self, Debug, Formatter};
use std::mem;
@ -870,6 +869,33 @@ 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" {
#[link_name = "llvm.fabs.v2f32"]
fn fabs_v2f32(a: float32x2_t) -> float32x2_t;

View File

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