diff --git a/Cargo.lock b/Cargo.lock index 5b82dce9..58c5f964 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "addr2line" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602d785912f476e480434627e8732e6766b760c045bbf897d9dfaa9f4fbd399c" +checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" dependencies = [ "gimli", ] @@ -135,14 +135,14 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "backtrace" -version = "0.3.49" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c" +checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" dependencies = [ "addr2line", "cfg-if", "libc 0.2.71", - "miniz_oxide 0.3.7", + "miniz_oxide 0.4.0", "object", "rustc-demangle", ] @@ -233,24 +233,6 @@ dependencies = [ "nix", ] -[[package]] -name = "canvas-webgl-minimal" -version = "0.1.0" -dependencies = [ - "pathfinder_canvas", - "pathfinder_color", - "pathfinder_content", - "pathfinder_geometry", - "pathfinder_gl", - "pathfinder_gpu", - "pathfinder_renderer", - "pathfinder_resources", - "pathfinder_webgl", - "wasm-bindgen", - "wasm-bindgen-test", - "web-sys", -] - [[package]] name = "canvas_glutin_minimal" version = "0.1.0" @@ -366,6 +348,24 @@ dependencies = [ "sdl2-sys", ] +[[package]] +name = "canvas_webgl_minimal" +version = "0.1.0" +dependencies = [ + "pathfinder_canvas", + "pathfinder_color", + "pathfinder_content", + "pathfinder_geometry", + "pathfinder_gl", + "pathfinder_gpu", + "pathfinder_renderer", + "pathfinder_resources", + "pathfinder_webgl", + "wasm-bindgen", + "wasm-bindgen-test", + "web-sys", +] + [[package]] name = "cbindgen" version = "0.13.2" @@ -418,9 +418,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0fee792e164f78f5fe0c296cc2eb3688a2ca2b70cdff33040922d298203f0c4" +checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6" dependencies = [ "num-integer", "num-traits 0.2.12", @@ -701,7 +701,7 @@ dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "lazy_static", + "lazy_static 1.4.0", "maybe-uninit", "memoffset", "scopeguard", @@ -726,7 +726,16 @@ checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ "autocfg", "cfg-if", - "lazy_static", + "lazy_static 1.4.0", +] + +[[package]] +name = "css-color-parser" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccb6ce7ef97e6dc6e575e51b596c9889a5cc88a307b5ef177d215c61fd7581d" +dependencies = [ + "lazy_static 0.1.16", ] [[package]] @@ -751,9 +760,9 @@ dependencies = [ [[package]] name = "deflate" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e5d2a2273fed52a7f947ee55b092c4057025d7a3e04e5ecdbd25d6c3fb1bd7" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" dependencies = [ "adler32", "byteorder", @@ -769,7 +778,7 @@ dependencies = [ "gl", "io-surface", "jemallocator", - "lazy_static", + "lazy_static 1.4.0", "metal 0.18.0", "nfd", "objc", @@ -851,7 +860,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcdf488e3a52a7aa30a05732a3e58420e22acb4b2b75635a561fc6ffbcab59ef" dependencies = [ - "lazy_static", + "lazy_static 1.4.0", "libc 0.2.71", "winapi 0.3.9", "wio", @@ -878,7 +887,7 @@ name = "encoding" version = "0.1.0" source = "git+https://github.com/pdf-rs/encoding/#44cafed01e9c40af58bd569a002c379e09da85bf" dependencies = [ - "lazy_static", + "lazy_static 1.4.0", ] [[package]] @@ -950,7 +959,7 @@ checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" [[package]] name = "font" version = "0.1.0" -source = "git+https://github.com/pdf-rs/font/#17d3c1d19d937440c760c79be373798326f02bcb" +source = "git+https://github.com/pdf-rs/font/#4c32bbab70d077cbf2322f500bb8c1a8f611fb75" dependencies = [ "brotli-decompressor", "decorum", @@ -985,7 +994,7 @@ dependencies = [ "dwrote", "float-ord", "freetype", - "lazy_static", + "lazy_static 1.4.0", "libc 0.2.71", "log", "pathfinder_geometry", @@ -1090,9 +1099,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" +checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" [[package]] name = "gl" @@ -1156,7 +1165,7 @@ dependencies = [ "glutin_gles2_sys", "glutin_glx_sys", "glutin_wgl_sys", - "lazy_static", + "lazy_static 1.4.0", "libloading 0.5.2", "log", "objc", @@ -1264,9 +1273,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ "libc 0.2.71", ] @@ -1324,9 +1333,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69da7ce1490173c2bf4d26bc8be429aaeeaf4cce6c4b970b7949651fa17655fe" +checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485" dependencies = [ "js-sys", "wasm-bindgen", @@ -1431,9 +1440,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jpeg-decoder" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b47b4c4e017b01abdc5bcc126d2d1002e5a75bbe3ce73f9f4f311a916363704" +checksum = "cc797adac5f083b8ff0ca6f6294a999393d76e197c36488e2ef732c4715f6fa3" dependencies = [ "byteorder", "rayon", @@ -1482,6 +1491,12 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "lazy_static" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417" + [[package]] name = "lazy_static" version = "1.4.0" @@ -1992,7 +2007,7 @@ dependencies = [ "cloudabi", "libc 0.2.71", "redox_syscall", - "smallvec 1.4.0", + "smallvec 1.4.1", "winapi 0.3.9", ] @@ -2003,7 +2018,7 @@ dependencies = [ "egl", "gl", "jni", - "lazy_static", + "lazy_static 1.4.0", "pathfinder_demo", "pathfinder_geometry", "pathfinder_gl", @@ -2068,7 +2083,7 @@ dependencies = [ "pathfinder_geometry", "pathfinder_simd", "quickcheck", - "smallvec 1.4.0", + "smallvec 1.4.1", ] [[package]] @@ -2175,7 +2190,7 @@ dependencies = [ "pathfinder_svg", "pathfinder_ui", "rayon", - "smallvec 1.4.0", + "smallvec 1.4.1", "usvg", ] @@ -2225,7 +2240,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "smallvec 1.4.0", + "smallvec 1.4.1", "vec_map", ] @@ -2294,6 +2309,25 @@ dependencies = [ "serde_json", ] +[[package]] +name = "pathfinder_web_canvas" +version = "0.1.0" +dependencies = [ + "css-color-parser", + "pathfinder_canvas", + "pathfinder_color", + "pathfinder_content", + "pathfinder_geometry", + "pathfinder_gl", + "pathfinder_gpu", + "pathfinder_renderer", + "pathfinder_resources", + "pathfinder_webgl", + "wasm-bindgen", + "wasm-bindgen-test", + "web-sys", +] + [[package]] name = "pathfinder_webgl" version = "0.1.0" @@ -2313,7 +2347,7 @@ dependencies = [ [[package]] name = "pdf" version = "0.7.0" -source = "git+https://github.com/pdf-rs/pdf#2beb20e6396722a1a6771d0caabc4fe6e05b671c" +source = "git+https://github.com/pdf-rs/pdf#249b9b0ac7d508344c2cdffd48c9e031763d0405" dependencies = [ "byteorder", "chrono", @@ -2335,7 +2369,7 @@ dependencies = [ [[package]] name = "pdf_derive" version = "0.1.19" -source = "git+https://github.com/pdf-rs/pdf#2beb20e6396722a1a6771d0caabc4fe6e05b671c" +source = "git+https://github.com/pdf-rs/pdf#249b9b0ac7d508344c2cdffd48c9e031763d0405" dependencies = [ "quote 1.0.7", "syn 1.0.33", @@ -2344,7 +2378,7 @@ dependencies = [ [[package]] name = "pdf_render" version = "0.1.0" -source = "git+https://github.com/pdf-rs/pdf#2beb20e6396722a1a6771d0caabc4fe6e05b671c" +source = "git+https://github.com/pdf-rs/pdf#249b9b0ac7d508344c2cdffd48c9e031763d0405" dependencies = [ "encoding", "font", @@ -2522,7 +2556,7 @@ dependencies = [ "crossbeam-deque", "crossbeam-queue", "crossbeam-utils", - "lazy_static", + "lazy_static 1.4.0", "num_cpus", ] @@ -2672,7 +2706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f74124048ea86b5cd50236b2443f6f57cf4625a8e8818009b4e50dbb8729a43" dependencies = [ "bitflags", - "lazy_static", + "lazy_static 1.4.0", "libc 0.2.71", "sdl2-sys", ] @@ -2770,7 +2804,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" dependencies = [ - "lazy_static", + "lazy_static 1.4.0", "libc 0.2.71", ] @@ -2826,9 +2860,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" +checksum = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f" [[package]] name = "smithay-client-toolkit" @@ -2839,7 +2873,7 @@ dependencies = [ "andrew", "bitflags", "dlib", - "lazy_static", + "lazy_static 1.4.0", "memmap", "nix", "wayland-client 0.21.13", @@ -2856,7 +2890,7 @@ dependencies = [ "andrew", "bitflags", "dlib", - "lazy_static", + "lazy_static 1.4.0", "memmap", "nix", "wayland-client 0.23.6", @@ -2921,7 +2955,7 @@ dependencies = [ "euclid", "gl_generator 0.13.1", "io-surface", - "lazy_static", + "lazy_static 1.4.0", "libc 0.2.71", "log", "mach", @@ -3064,7 +3098,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" dependencies = [ - "lazy_static", + "lazy_static 1.4.0", ] [[package]] @@ -3258,7 +3292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e53963b583d18a5aa3aaae4b4c1cb535218246131ba22a71f05b518098571df" dependencies = [ "bumpalo", - "lazy_static", + "lazy_static 1.4.0", "log", "proc-macro2 1.0.18", "quote 1.0.7", @@ -3437,7 +3471,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520ab0fd578017a0ee2206623ba9ef4afe5e8f23ca7b42f6acfba2f4e66b1628" dependencies = [ "dlib", - "lazy_static", + "lazy_static 1.4.0", ] [[package]] @@ -3447,7 +3481,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4" dependencies = [ "dlib", - "lazy_static", + "lazy_static 1.4.0", ] [[package]] @@ -3457,7 +3491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "537500923d50be11d95a63c4cb538145e4c82edf61296b7debc1f94a1a6514ed" dependencies = [ "dlib", - "lazy_static", + "lazy_static 1.4.0", ] [[package]] @@ -3525,7 +3559,7 @@ dependencies = [ "cocoa 0.18.5", "core-foundation 0.6.4", "core-graphics 0.17.3", - "lazy_static", + "lazy_static 1.4.0", "libc 0.2.71", "log", "objc", @@ -3551,7 +3585,7 @@ dependencies = [ "core-video-sys", "dispatch", "instant", - "lazy_static", + "lazy_static 1.4.0", "libc 0.2.71", "log", "mio", @@ -3601,7 +3635,7 @@ version = "2.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf981e3a5b3301209754218f962052d4d9ee97e478f4d26d4a6eced34c1fef8" dependencies = [ - "lazy_static", + "lazy_static 1.4.0", "libc 0.2.71", "maybe-uninit", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index ba95ebaa..eae6fb47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ members = [ "utils/gamma-lut", "utils/svg-to-skia", "utils/convert", + "web_canvas", "webgl", ] diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index 3dc0a8bc..897b96f1 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -89,6 +89,22 @@ impl Canvas { Canvas { scene } } + /// Returns the inner scene. + #[inline] + pub fn scene(&self) -> &Scene { + &self.scene + } + + /// Returns the inner scene, replacing it with a blank scene. + #[inline] + pub fn take_scene(&mut self) -> Scene { + let view_box = self.scene.view_box(); + let mut new_scene = Scene::new(); + new_scene.set_view_box(view_box); + mem::replace(&mut self.scene, new_scene) + } + + /// Destroys this canvas and returns the inner scene. #[inline] pub fn into_scene(self) -> Scene { self.scene @@ -113,6 +129,12 @@ impl Canvas { pub fn size(&self) -> Vector2I { self.scene.view_box().size().ceil().to_i32() } + + pub fn set_size(&mut self, new_size: Vector2I) { + let new_view_box = RectI::new(Vector2I::default(), new_size).to_f32(); + self.scene.set_bounds(new_view_box); + self.scene.set_view_box(new_view_box); + } } pub struct CanvasRenderingContext2D { @@ -131,11 +153,23 @@ impl CanvasRenderingContext2D { &self.canvas } + #[inline] + pub fn canvas_mut(&mut self) -> &mut Canvas { + &mut self.canvas + } + #[inline] pub fn into_canvas(self) -> Canvas { self.canvas } + // Extensions + + /// Clears the current canvas. + pub fn clear(&mut self) { + drop(self.canvas.take_scene()) + } + // Drawing rectangles #[inline] @@ -170,26 +204,51 @@ impl CanvasRenderingContext2D { // Line styles + #[inline] + pub fn line_width(&self) -> f32 { + self.current_state.line_width + } + #[inline] pub fn set_line_width(&mut self, new_line_width: f32) { self.current_state.line_width = new_line_width } + #[inline] + pub fn line_cap(&self) -> LineCap { + self.current_state.line_cap + } + #[inline] pub fn set_line_cap(&mut self, new_line_cap: LineCap) { self.current_state.line_cap = new_line_cap } + #[inline] + pub fn line_join(&self) -> LineJoin { + self.current_state.line_join + } + #[inline] pub fn set_line_join(&mut self, new_line_join: LineJoin) { self.current_state.line_join = new_line_join } + #[inline] + pub fn miter_limit(&self) -> f32 { + self.current_state.miter_limit + } + #[inline] pub fn set_miter_limit(&mut self, new_miter_limit: f32) { self.current_state.miter_limit = new_miter_limit } + #[inline] + pub fn line_dash(&mut self) -> &[f32] { + &self.current_state.line_dash + } + #[inline] pub fn set_line_dash(&mut self, mut new_line_dash: Vec) { // Duplicate and concatenate if an odd number of dashes are present. @@ -202,6 +261,11 @@ impl CanvasRenderingContext2D { self.current_state.line_dash = new_line_dash } + #[inline] + pub fn line_dash_offset(&self) -> f32 { + self.current_state.line_dash_offset + } + #[inline] pub fn set_line_dash_offset(&mut self, new_line_dash_offset: f32) { self.current_state.line_dash_offset = new_line_dash_offset @@ -657,7 +721,6 @@ impl Path2D { #[inline] pub fn move_to(&mut self, to: Vector2F) { - // TODO(pcwalton): Cull degenerate contours. self.flush_current_contour(); self.current_contour.push_endpoint(to); } diff --git a/canvas/src/text.rs b/canvas/src/text.rs index 44af8a19..2192413e 100644 --- a/canvas/src/text.rs +++ b/canvas/src/text.rs @@ -446,29 +446,6 @@ impl IntoFontCollection for Vec { } } -/* -impl IntoFontCollection for Handle { - #[inline] - fn into_font_collection(self, context: &CanvasFontContext) -> Arc { - self.load().expect("Failed to load the font!").into_font_collection(context) - } -} - -impl<'a> IntoFontCollection for &'a [Handle] { - #[inline] - fn into_font_collection(self, context: &CanvasFontContext) -> Arc { - let mut font_collection = FontCollection::new(); - for handle in self { - let postscript_name = handle.postscript_name(); - - let font = handle.load().expect("Failed to load the font!"); - font_collection.add_family(FontFamily::new_from_font(font)); - } - Arc::new(font_collection) - } -} -*/ - impl IntoFontCollection for Font { #[inline] fn into_font_collection(self, context: &CanvasFontContext) -> Arc { diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 2169d50e..e93b0fe0 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -301,7 +301,9 @@ impl DemoApp where W: Window { let viewport = self.window.viewport(self.ui_model.mode.view(0)); self.scene_proxy.set_view_box(RectF::new(Vector2F::zero(), viewport.size().to_f32())); - self.renderer.set_main_framebuffer_size(self.window_size.device_size()); + self.renderer.options_mut().dest = + DestFramebuffer::full_window(self.window_size.device_size()); + self.renderer.dest_framebuffer_size_changed(); self.dirty = true; } Event::MouseDown(new_position) => { diff --git a/examples/canvas_webgl_minimal/Cargo.toml b/examples/canvas_webgl_minimal/Cargo.toml index 501f7ef5..5aec1bad 100644 --- a/examples/canvas_webgl_minimal/Cargo.toml +++ b/examples/canvas_webgl_minimal/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "canvas-webgl-minimal" +name = "canvas_webgl_minimal" version = "0.1.0" authors = ["Patrick Walton "] edition = "2018" @@ -11,7 +11,7 @@ crate-type = ["cdylib", "rlib"] default = [] [dependencies] -wasm-bindgen = "0.2.63" +wasm-bindgen = "0.2" [dependencies.pathfinder_canvas] path = "../../canvas" @@ -45,7 +45,7 @@ version = "0.3" features = ["Window"] [dev-dependencies] -wasm-bindgen-test = "0.3.13" +wasm-bindgen-test = "0.3" [profile.release] # Tell `rustc` to optimize for small code size. diff --git a/examples/canvas_webgl_minimal/src/lib.rs b/examples/canvas_webgl_minimal/src/lib.rs index 317e3356..bfa17b37 100644 --- a/examples/canvas_webgl_minimal/src/lib.rs +++ b/examples/canvas_webgl_minimal/src/lib.rs @@ -24,11 +24,6 @@ use web_sys::{self, HtmlCanvasElement, WebGl2RenderingContext}; mod utils; -#[wasm_bindgen] -extern { - fn alert(s: &str); -} - #[wasm_bindgen] pub fn rust_main() { utils::set_panic_hook(); diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index 01a54912..d3ed432b 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -290,6 +290,10 @@ impl Renderer where D: Device { } } + pub fn destroy(self) -> D { + self.core.device + } + pub fn begin_scene(&mut self) { self.core.framebuffer_flags = FramebufferFlags::empty(); @@ -485,7 +489,8 @@ impl Renderer where D: Device { } #[inline] - pub fn set_main_framebuffer_size(&mut self, new_framebuffer_size: Vector2I) { + pub fn dest_framebuffer_size_changed(&mut self) { + let new_framebuffer_size = self.core.main_viewport().size(); if let Some(ref mut debug_ui_presenter) = self.debug_ui_presenter { debug_ui_presenter.ui_presenter.set_framebuffer_size(new_framebuffer_size); } diff --git a/web_canvas/Cargo.toml b/web_canvas/Cargo.toml new file mode 100644 index 00000000..36ce35e5 --- /dev/null +++ b/web_canvas/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "pathfinder_web_canvas" +version = "0.1.0" +authors = ["Patrick Walton "] +edition = "2018" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +css-color-parser = "0.1" +wasm-bindgen = "0.2" + +[dependencies.pathfinder_canvas] +path = "../canvas" + +[dependencies.pathfinder_color] +path = "../color" + +[dependencies.pathfinder_content] +path = "../content" + +[dependencies.pathfinder_geometry] +path = "../geometry" + +[dependencies.pathfinder_gl] +path = "../gl" + +[dependencies.pathfinder_gpu] +path = "../gpu" + +[dependencies.pathfinder_renderer] +path = "../renderer" + +[dependencies.pathfinder_resources] +path = "../resources" + +[dependencies.pathfinder_webgl] +path = "../webgl" + +[dependencies.web-sys] +version = "0.3" +features = ["Window", "console"] + +[dev-dependencies] +wasm-bindgen-test = "0.3" + +[profile.release] +# Tell `rustc` to optimize for small code size. +# opt-level = "s" +debug = 1 + +[package.metadata.wasm-pack.profile.profiling] +wasm-opt = false +dwarf-debug-info = true + +[package.metadata.wasm-pack.profile.profiling.wasm-bindgen] +debug-js-glue = false +demangle-name-section = true +dwarf-debug-info = true diff --git a/web_canvas/src/lib.rs b/web_canvas/src/lib.rs new file mode 100644 index 00000000..e2b908a6 --- /dev/null +++ b/web_canvas/src/lib.rs @@ -0,0 +1,268 @@ +// pathfinder/web_canvas/src/lib.rs +// +// Copyright © 2020 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use css_color_parser::Color; +use pathfinder_canvas::{Canvas, CanvasFontContext, CanvasRenderingContext2D, FillRule, FillStyle}; +use pathfinder_canvas::{LineCap, Path2D}; +use pathfinder_color::ColorU; +use pathfinder_geometry::rect::RectF; +use pathfinder_geometry::transform2d::Transform2F; +use pathfinder_geometry::vector::{vec2f, vec2i}; +use pathfinder_renderer::concurrent::executor::SequentialExecutor; +use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions}; +use pathfinder_renderer::gpu::renderer::Renderer; +use pathfinder_renderer::options::BuildOptions; +use pathfinder_resources::embedded::EmbeddedResourceLoader; +use pathfinder_webgl::WebGlDevice; +use std::str::FromStr; +use std::sync::Arc; +use wasm_bindgen::JsCast; +use wasm_bindgen::prelude::*; +use web_sys::{self, HtmlCanvasElement, WebGl2RenderingContext}; + +#[wasm_bindgen] +pub struct PFCanvasRenderingContext2D { + html_canvas: HtmlCanvasElement, + context: CanvasRenderingContext2D, + renderer: Renderer, + default_path: Path2D, + current_state: WebCanvasState, + saved_states: Vec, +} + +#[derive(Clone)] +struct WebCanvasState { + fill_style_string: Arc, + stroke_style_string: Arc, +} + +#[wasm_bindgen(js_name = "createContext")] +pub fn create_context(html_canvas: HtmlCanvasElement) -> PFCanvasRenderingContext2D { + let context = html_canvas.get_context("webgl2") + .unwrap() + .unwrap() + .dyn_into::() + .unwrap(); + + // Get the real size of the window, taking HiDPI into account. + let framebuffer_size = vec2i(html_canvas.width() as i32, html_canvas.height() as i32); + + // Create a Pathfinder GL device. + let pathfinder_device = WebGlDevice::new(context); + + // Create a Pathfinder renderer. + let mode = RendererMode::default_for_device(&pathfinder_device); + let options = RendererOptions { + dest: DestFramebuffer::full_window(framebuffer_size), + background_color: None, + ..RendererOptions::default() + }; + let resource_loader = EmbeddedResourceLoader::new(); + let renderer = Renderer::new(pathfinder_device, &resource_loader, mode, options); + + // Make a canvas. + let font_context = CanvasFontContext::from_system_source(); + let context = Canvas::new(framebuffer_size.to_f32()).get_context_2d(font_context); + + PFCanvasRenderingContext2D { + html_canvas, + context, + renderer, + default_path: Path2D::new(), + current_state: WebCanvasState { + fill_style_string: Arc::new("black".to_owned()), + stroke_style_string: Arc::new("black".to_owned()), + }, + saved_states: vec![], + } +} + +#[wasm_bindgen] +impl PFCanvasRenderingContext2D { + #[wasm_bindgen(js_name = "pfFlush")] + pub fn pf_flush(&mut self) { + // Update framebuffer size. + let framebuffer_size = vec2i(self.html_canvas.width() as i32, + self.html_canvas.height() as i32); + self.renderer.options_mut().dest = DestFramebuffer::full_window(framebuffer_size); + self.renderer.options_mut().background_color = None; + self.renderer.dest_framebuffer_size_changed(); + + // TODO(pcwalton): This is inefficient! + let mut scene = (*self.context.canvas_mut().scene()).clone(); + scene.build_and_render(&mut self.renderer, BuildOptions::default(), SequentialExecutor); + + self.context.canvas_mut().set_size(framebuffer_size); + } + + #[wasm_bindgen(js_name = "pfClear")] + pub fn pf_clear(&mut self) { + self.context.clear(); + } + + #[wasm_bindgen(getter)] + pub fn canvas(&self) -> HtmlCanvasElement { + self.html_canvas.clone() + } + + // Drawing rectangles + + #[wasm_bindgen(js_name = "clearRect")] + pub fn clear_rect(&mut self, x: f32, y: f32, width: f32, height: f32) { + self.context.clear_rect(RectF::new(vec2f(x, y), vec2f(width, height))); + } + + #[wasm_bindgen(js_name = "fillRect")] + pub fn fill_rect(&mut self, x: f32, y: f32, width: f32, height: f32) { + self.context.fill_rect(RectF::new(vec2f(x, y), vec2f(width, height))); + } + + #[wasm_bindgen(js_name = "strokeRect")] + pub fn stroke_rect(&mut self, x: f32, y: f32, width: f32, height: f32) { + self.context.stroke_rect(RectF::new(vec2f(x, y), vec2f(width, height))); + } + + // TODO(pcwalton): Drawing text + + // Line styles + + #[wasm_bindgen(js_name = "lineWidth")] + #[wasm_bindgen(getter)] + pub fn line_width(&self) -> f32 { + self.context.line_width() + } + + #[wasm_bindgen(js_name = "lineWidth")] + #[wasm_bindgen(setter)] + pub fn set_line_width(&mut self, new_line_width: f32) { + self.context.set_line_width(new_line_width); + } + + #[wasm_bindgen(js_name = "lineCap")] + #[wasm_bindgen(getter)] + pub fn line_cap(&self) -> String { + match self.context.line_cap() { + LineCap::Butt => "butt".to_owned(), + LineCap::Round => "round".to_owned(), + LineCap::Square => "square".to_owned(), + } + } + + #[wasm_bindgen(js_name = "lineCap")] + #[wasm_bindgen(setter)] + pub fn set_line_cap(&mut self, new_line_cap: &str) { + if new_line_cap == "butt" { + self.context.set_line_cap(LineCap::Butt) + } else if new_line_cap == "round" { + self.context.set_line_cap(LineCap::Round) + } else if new_line_cap == "square" { + self.context.set_line_cap(LineCap::Square) + } + } + + #[wasm_bindgen(js_name = "fillStyle")] + #[wasm_bindgen(setter)] + pub fn set_fill_style(&mut self, new_style_string: &str) { + if let Some(new_style) = parse_fill_or_stroke_style(new_style_string) { + self.context.set_fill_style(new_style); + self.current_state.fill_style_string = Arc::new(new_style_string.to_owned()); + } + } + + #[wasm_bindgen(js_name = "strokeStyle")] + #[wasm_bindgen(setter)] + pub fn set_stroke_style(&mut self, new_style_string: &str) { + if let Some(new_style) = parse_fill_or_stroke_style(new_style_string) { + self.context.set_stroke_style(new_style); + self.current_state.stroke_style_string = Arc::new(new_style_string.to_owned()); + } + } + + pub fn transform(&mut self, a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) { + let new_transform = self.context.transform() * Transform2F::row_major(a, c, e, b, d, f); + self.context.set_transform(&new_transform) + } + + pub fn translate(&mut self, x: f32, y: f32) { + self.context.translate(vec2f(x, y)) + } + + pub fn scale(&mut self, x: f32, y: f32) { + self.context.scale(vec2f(x, y)) + } + + pub fn rotate(&mut self, angle: f32) { + self.context.rotate(angle) + } + + #[wasm_bindgen(js_name = "beginPath")] + pub fn begin_path(&mut self) { + self.default_path = Path2D::new(); + } + + #[wasm_bindgen(js_name = "moveTo")] + pub fn move_to(&mut self, x: f32, y: f32) { + self.default_path.move_to(vec2f(x, y)) + } + + #[wasm_bindgen(js_name = "lineTo")] + pub fn line_to(&mut self, x: f32, y: f32) { + self.default_path.line_to(vec2f(x, y)) + } + + #[wasm_bindgen(js_name = "bezierCurveTo")] + pub fn bezier_curve_to(&mut self, cp1x: f32, cp1y: f32, cp2x: f32, cp2y: f32, x: f32, y: f32) { + self.default_path.bezier_curve_to(vec2f(cp1x, cp1y), vec2f(cp2x, cp2y), vec2f(x, y)) + } + + #[wasm_bindgen(js_name = "quadraticCurveTo")] + pub fn quadratic_curve_to(&mut self, cpx: f32, cpy: f32, x: f32, y: f32) { + self.default_path.quadratic_curve_to(vec2f(cpx, cpy), vec2f(x, y)) + } + + #[wasm_bindgen(js_name = "closePath")] + pub fn close_path(&mut self) { + self.default_path.close_path(); + } + + pub fn fill(&mut self) { + let path = self.default_path.clone(); + self.context.fill_path(path, FillRule::Winding); + } + + pub fn stroke(&mut self) { + let path = self.default_path.clone(); + self.context.stroke_path(path); + } + + pub fn save(&mut self) { + self.context.save(); + self.saved_states.push(self.current_state.clone()); + } + + pub fn restore(&mut self) { + if let Some(saved_state) = self.saved_states.pop() { + self.current_state = saved_state; + } + self.context.restore(); + } +} + +fn parse_fill_or_stroke_style(string: &str) -> Option { + let css_color = match Color::from_str(string) { + Err(_) => return None, + Ok(css_color) => css_color, + }; + let color = ColorU::new(css_color.r, + css_color.g, + css_color.b, + (css_color.a * 255.0).round() as u8); + Some(FillStyle::Color(color)) +}