Pass in the font context to the canvas rendering context constructor so that it

can be reused.

Creating a system font source can do I/O on some platforms, so obviously we
don't want to do it every frame.
This commit is contained in:
Patrick Walton 2019-05-29 21:15:03 -07:00
parent e1bcc11ace
commit 9138e1e0bb
7 changed files with 67 additions and 35 deletions

View File

@ -39,6 +39,8 @@ struct PFCanvas;
typedef struct PFCanvas *PFCanvasRef;
struct PFPath;
typedef struct PFPath *PFPathRef;
struct PFCanvasFontContext;
typedef struct PFCanvasFontContext *PFCanvasFontContextRef;
// `geometry`
@ -103,8 +105,10 @@ typedef struct PFSceneProxy *PFSceneProxyRef;
// `canvas`
PFCanvasRef PFCanvasCreate(const PFPoint2DF *size);
PFCanvasRef PFCanvasCreate(PFCanvasFontContextRef font_context, const PFPoint2DF *size);
void PFCanvasDestroy(PFCanvasRef canvas);
PFCanvasFontContextRef PFCanvasFontContextCreate();
void PFCanvasFontContextDestroy(PFCanvasFontContextRef font_context);
PFSceneRef PFCanvasCreateScene(PFCanvasRef canvas);
void PFCanvasFillRect(PFCanvasRef canvas, const PFRectF *rect);
void PFCanvasStrokeRect(PFCanvasRef canvas, const PFRectF *rect);

View File

@ -11,7 +11,7 @@
//! C bindings to Pathfinder.
use gl;
use pathfinder_canvas::{CanvasRenderingContext2D, Path2D};
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D};
use pathfinder_geometry::basic::point::{Point2DF, Point2DI};
use pathfinder_geometry::basic::rect::{RectF, RectI};
use pathfinder_geometry::color::ColorF;
@ -39,6 +39,7 @@ pub const PF_CLEAR_FLAGS_HAS_RECT: u8 = 0x8;
// `canvas`
pub type PFCanvasRef = *mut CanvasRenderingContext2D;
pub type PFPathRef = *mut Path2D;
pub type PFCanvasFontContextRef = *mut CanvasFontContext;
// `geometry`
#[repr(C)]
@ -102,8 +103,11 @@ pub struct PFRenderOptions {
// `canvas`
#[no_mangle]
pub unsafe extern "C" fn PFCanvasCreate(size: *const PFPoint2DF) -> PFCanvasRef {
Box::into_raw(Box::new(CanvasRenderingContext2D::new((*size).to_rust())))
pub unsafe extern "C" fn PFCanvasCreate(font_context: PFCanvasFontContextRef,
size: *const PFPoint2DF)
-> PFCanvasRef {
Box::into_raw(Box::new(CanvasRenderingContext2D::new(*Box::from_raw(font_context),
(*size).to_rust())))
}
#[no_mangle]
@ -111,6 +115,16 @@ pub unsafe extern "C" fn PFCanvasDestroy(canvas: PFCanvasRef) {
drop(Box::from_raw(canvas))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFontContextCreate() -> PFCanvasFontContextRef {
Box::into_raw(Box::new(CanvasFontContext::new()))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFontContextDestroy(font_context: PFCanvasFontContextRef) {
drop(Box::from_raw(font_context))
}
/// Consumes the canvas.
#[no_mangle]
pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef {

View File

@ -35,41 +35,24 @@ pub struct CanvasRenderingContext2D {
scene: Scene,
current_state: State,
saved_states: Vec<State>,
#[allow(dead_code)]
font_source: SystemSource,
#[allow(dead_code)]
default_font_collection: Arc<FontCollection>,
font_context: CanvasFontContext,
}
impl CanvasRenderingContext2D {
#[inline]
pub fn new(size: Point2DF) -> CanvasRenderingContext2D {
pub fn new(font_context: CanvasFontContext, size: Point2DF) -> CanvasRenderingContext2D {
let mut scene = Scene::new();
scene.set_view_box(RectF::new(Point2DF::default(), size));
CanvasRenderingContext2D::from_scene(scene)
CanvasRenderingContext2D::from_scene(font_context, scene)
}
pub fn from_scene(scene: Scene) -> CanvasRenderingContext2D {
// TODO(pcwalton): Allow the user to cache this?
let font_source = SystemSource::new();
let mut default_font_collection = FontCollection::new();
let default_font =
font_source.select_best_match(&[FamilyName::SansSerif], &Properties::new())
.expect("Failed to select the default font!")
.load()
.expect("Failed to load the default font!");
default_font_collection.add_family(FontFamily::new_from_font(default_font));
let default_font_collection = Arc::new(default_font_collection);
pub fn from_scene(font_context: CanvasFontContext, scene: Scene) -> CanvasRenderingContext2D {
CanvasRenderingContext2D {
scene,
current_state: State::default(default_font_collection.clone()),
current_state: State::default(font_context.default_font_collection.clone()),
saved_states: vec![],
font_source,
default_font_collection,
font_context,
}
}
@ -335,3 +318,31 @@ impl FillStyle {
match *self { FillStyle::Color(color) => Paint { color } }
}
}
#[derive(Clone)]
pub struct CanvasFontContext {
#[allow(dead_code)]
font_source: Arc<SystemSource>,
#[allow(dead_code)]
default_font_collection: Arc<FontCollection>,
}
impl CanvasFontContext {
pub fn new() -> CanvasFontContext {
let font_source = Arc::new(SystemSource::new());
let mut default_font_collection = FontCollection::new();
let default_font =
font_source.select_best_match(&[FamilyName::SansSerif], &Properties::new())
.expect("Failed to select the default font!")
.load()
.expect("Failed to load the default font!");
default_font_collection.add_family(FontFamily::new_from_font(default_font));
let default_font_collection = Arc::new(default_font_collection);
CanvasFontContext {
font_source,
default_font_collection,
}
}
}

View File

@ -66,7 +66,8 @@ int main(int argc, const char **argv) {
});
// Make a canvas. We're going to draw a house.
PFCanvasRef canvas = PFCanvasCreate(&(PFPoint2DF){640.0f, 480.0f});
PFCanvasRef canvas = PFCanvasCreate(PFCanvasFontContextCreate(),
&(PFPoint2DF){640.0f, 480.0f});
// Set line width.
PFCanvasSetLineWidth(canvas, 10.0f);

View File

@ -8,11 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use pathfinder_canvas::{CanvasRenderingContext2D, Path2D};
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D};
use pathfinder_geometry::basic::point::{Point2DF, Point2DI};
use pathfinder_geometry::basic::rect::RectF;
use pathfinder_geometry::color::ColorF;
use pathfinder_geometry::stroke::LineJoin;
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_gpu::resources::FilesystemResourceLoader;
use pathfinder_gpu::{ClearParams, Device};
@ -55,7 +54,7 @@ fn main() {
renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() });
// Make a canvas. We're going to draw a house.
let mut canvas = CanvasRenderingContext2D::new(window_size.to_f32());
let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32());
// Set line width.
canvas.set_line_width(10.0);

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use pathfinder_canvas::{CanvasRenderingContext2D, FillStyle, Path2D};
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, FillStyle, Path2D};
use pathfinder_geometry::basic::point::{Point2DF, Point2DI};
use pathfinder_geometry::color::{ColorF, ColorU};
use pathfinder_gl::{GLDevice, GLVersion};
@ -85,6 +85,7 @@ fn main() {
struct MoireRenderer {
renderer: Renderer<GLDevice>,
font_context: CanvasFontContext,
scene: SceneProxy,
frame: i32,
window_size: Point2DI,
@ -98,6 +99,7 @@ impl MoireRenderer {
-> MoireRenderer {
MoireRenderer {
renderer,
font_context: CanvasFontContext::new(),
scene: SceneProxy::new(RayonExecutor),
frame: 0,
window_size,
@ -128,7 +130,8 @@ impl MoireRenderer {
});
// Make a canvas.
let mut canvas = CanvasRenderingContext2D::new(self.drawable_size.to_f32());
let mut canvas = CanvasRenderingContext2D::new(self.font_context.clone(),
self.drawable_size.to_f32());
canvas.set_line_width(CIRCLE_THICKNESS * self.device_pixel_ratio);
canvas.set_stroke_style(FillStyle::Color(foreground_color.to_u8()));
canvas.set_global_alpha(0.75);

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use pathfinder_canvas::CanvasRenderingContext2D;
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D};
use pathfinder_geometry::basic::point::{Point2DF, Point2DI};
use pathfinder_geometry::color::ColorF;
use pathfinder_gl::{GLDevice, GLVersion};
@ -53,7 +53,7 @@ fn main() {
renderer.device.clear(&ClearParams { color: Some(ColorF::white()), ..ClearParams::default() });
// Make a canvas. We're going to draw some text.
let mut canvas = CanvasRenderingContext2D::new(window_size.to_f32());
let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::new(), window_size.to_f32());
// Draw the text.
canvas.set_font_size(32.0);