Add reformat to the CI (#21)
This commit is contained in:
parent
df091d59dd
commit
5674886dfa
7 changed files with 112 additions and 78 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
use std::f64::consts::PI;
|
|
||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
use std::f64::consts::PI;
|
||||||
use swbuf::GraphicsContext;
|
use swbuf::GraphicsContext;
|
||||||
use winit::event::{Event, WindowEvent};
|
use winit::event::{Event, WindowEvent};
|
||||||
use winit::event_loop::{ControlFlow, EventLoop};
|
use winit::event_loop::{ControlFlow, EventLoop};
|
||||||
|
|
@ -42,12 +42,12 @@ fn main() {
|
||||||
(size.width, size.height)
|
(size.width, size.height)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (width, height) != old_size{
|
if (width, height) != old_size {
|
||||||
old_size = (width, height);
|
old_size = (width, height);
|
||||||
frames = pre_render_frames(width as usize, height as usize);
|
frames = pre_render_frames(width as usize, height as usize);
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer = &frames[((elapsed*60.0).round() as usize).clamp(0, 59)];
|
let buffer = &frames[((elapsed * 60.0).round() as usize).clamp(0, 59)];
|
||||||
graphics_context.set_buffer(buffer.as_slice(), width as u16, height as u16);
|
graphics_context.set_buffer(buffer.as_slice(), width as u16, height as u16);
|
||||||
}
|
}
|
||||||
Event::MainEventsCleared => {
|
Event::MainEventsCleared => {
|
||||||
|
|
@ -64,17 +64,20 @@ fn main() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_render_frames(width: usize, height: usize) -> Vec<Vec<u32>>{
|
fn pre_render_frames(width: usize, height: usize) -> Vec<Vec<u32>> {
|
||||||
let render = |frame_id|{
|
let render = |frame_id| {
|
||||||
let elapsed = ((frame_id as f64)/(60.0))*2.0*PI;
|
let elapsed = ((frame_id as f64) / (60.0)) * 2.0 * PI;
|
||||||
|
|
||||||
(0..(width * height))
|
(0..(width * height))
|
||||||
.map(|index| {
|
.map(|index| {
|
||||||
let y = ((index / width) as f64)/(height as f64);
|
let y = ((index / width) as f64) / (height as f64);
|
||||||
let x = ((index % width) as f64)/(width as f64);
|
let x = ((index % width) as f64) / (width as f64);
|
||||||
let red = ((((y + elapsed).sin()*0.5+0.5)*255.0).round() as u32).clamp(0, 255);
|
let red =
|
||||||
let green = ((((x + elapsed).sin()*0.5+0.5)*255.0).round() as u32).clamp(0, 255);
|
((((y + elapsed).sin() * 0.5 + 0.5) * 255.0).round() as u32).clamp(0, 255);
|
||||||
let blue = ((((y - elapsed).cos()*0.5+0.5)*255.0).round() as u32).clamp(0, 255);
|
let green =
|
||||||
|
((((x + elapsed).sin() * 0.5 + 0.5) * 255.0).round() as u32).clamp(0, 255);
|
||||||
|
let blue =
|
||||||
|
((((y - elapsed).cos() * 0.5 + 0.5) * 255.0).round() as u32).clamp(0, 255);
|
||||||
|
|
||||||
blue | (green << 8) | (red << 16)
|
blue | (green << 8) | (red << 16)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,16 @@ use winit::window::WindowBuilder;
|
||||||
fn main() {
|
fn main() {
|
||||||
//see fruit.jpg.license for the license of fruit.jpg
|
//see fruit.jpg.license for the license of fruit.jpg
|
||||||
let fruit = image::load_from_memory(include_bytes!("fruit.jpg")).unwrap();
|
let fruit = image::load_from_memory(include_bytes!("fruit.jpg")).unwrap();
|
||||||
let buffer = fruit.pixels().map(|(_x, _y, pixel)|{
|
let buffer = fruit
|
||||||
let red = pixel.0[0] as u32;
|
.pixels()
|
||||||
let green = pixel.0[1] as u32;
|
.map(|(_x, _y, pixel)| {
|
||||||
let blue = pixel.0[2] as u32;
|
let red = pixel.0[0] as u32;
|
||||||
|
let green = pixel.0[1] as u32;
|
||||||
|
let blue = pixel.0[2] as u32;
|
||||||
|
|
||||||
blue | (green << 8) | (red << 16)
|
blue | (green << 8) | (red << 16)
|
||||||
}).collect::<Vec<_>>();
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
let window = WindowBuilder::new()
|
let window = WindowBuilder::new()
|
||||||
|
|
|
||||||
15
src/cg.rs
15
src/cg.rs
|
|
@ -1,12 +1,14 @@
|
||||||
use crate::SwBufError;
|
use crate::SwBufError;
|
||||||
use raw_window_handle::AppKitWindowHandle;
|
use core_graphics::base::{
|
||||||
use core_graphics::base::{kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault};
|
kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault,
|
||||||
|
};
|
||||||
use core_graphics::color_space::CGColorSpace;
|
use core_graphics::color_space::CGColorSpace;
|
||||||
use core_graphics::data_provider::CGDataProvider;
|
use core_graphics::data_provider::CGDataProvider;
|
||||||
use core_graphics::image::CGImage;
|
use core_graphics::image::CGImage;
|
||||||
|
use raw_window_handle::AppKitWindowHandle;
|
||||||
|
|
||||||
|
use cocoa::appkit::{NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow};
|
||||||
use cocoa::base::{id, nil};
|
use cocoa::base::{id, nil};
|
||||||
use cocoa::appkit::{NSView, NSViewWidthSizable, NSViewHeightSizable, NSWindow};
|
|
||||||
use cocoa::quartzcore::{CALayer, ContentsGravity};
|
use cocoa::quartzcore::{CALayer, ContentsGravity};
|
||||||
use foreign_types::ForeignType;
|
use foreign_types::ForeignType;
|
||||||
|
|
||||||
|
|
@ -30,14 +32,13 @@ impl CGImpl {
|
||||||
|
|
||||||
view.addSubview_(subview); // retains subview (+1) = 2
|
view.addSubview_(subview); // retains subview (+1) = 2
|
||||||
let _: () = msg_send![subview, release]; // releases subview (-1) = 1
|
let _: () = msg_send![subview, release]; // releases subview (-1) = 1
|
||||||
Ok(Self{layer})
|
Ok(Self { layer })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
|
pub(crate) unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
|
||||||
let color_space = CGColorSpace::create_device_rgb();
|
let color_space = CGColorSpace::create_device_rgb();
|
||||||
let data = std::slice::from_raw_parts(
|
let data =
|
||||||
buffer.as_ptr() as *const u8,
|
std::slice::from_raw_parts(buffer.as_ptr() as *const u8, buffer.len() * 4).to_vec();
|
||||||
buffer.len() * 4).to_vec();
|
|
||||||
let data_provider = CGDataProvider::from_buffer(Arc::new(data));
|
let data_provider = CGDataProvider::from_buffer(Arc::new(data));
|
||||||
let image = CGImage::new(
|
let image = CGImage::new(
|
||||||
width as usize,
|
width as usize,
|
||||||
|
|
|
||||||
18
src/error.rs
18
src/error.rs
|
|
@ -1,5 +1,5 @@
|
||||||
use std::error::Error;
|
|
||||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||||
|
use std::error::Error;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
|
@ -12,7 +12,7 @@ pub enum SwBufError {
|
||||||
human_readable_window_platform_name: &'static str,
|
human_readable_window_platform_name: &'static str,
|
||||||
human_readable_display_platform_name: &'static str,
|
human_readable_display_platform_name: &'static str,
|
||||||
window_handle: RawWindowHandle,
|
window_handle: RawWindowHandle,
|
||||||
display_handle: RawDisplayHandle
|
display_handle: RawDisplayHandle,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("The provided window handle is null.")]
|
#[error("The provided window handle is null.")]
|
||||||
|
|
@ -22,13 +22,19 @@ pub enum SwBufError {
|
||||||
IncompleteDisplayHandle,
|
IncompleteDisplayHandle,
|
||||||
|
|
||||||
#[error("Platform error")]
|
#[error("Platform error")]
|
||||||
PlatformError(Option<String>, Option<Box<dyn Error>>)
|
PlatformError(Option<String>, Option<Box<dyn Error>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)] // This isn't used on all platforms
|
#[allow(unused)] // This isn't used on all platforms
|
||||||
pub(crate) fn unwrap<T, E: std::error::Error + 'static>(res: Result<T, E>, str: &str) -> Result<T, SwBufError>{
|
pub(crate) fn unwrap<T, E: std::error::Error + 'static>(
|
||||||
match res{
|
res: Result<T, E>,
|
||||||
|
str: &str,
|
||||||
|
) -> Result<T, SwBufError> {
|
||||||
|
match res {
|
||||||
Ok(t) => Ok(t),
|
Ok(t) => Ok(t),
|
||||||
Err(e) => Err(SwBufError::PlatformError(Some(str.into()), Some(Box::new(e))))
|
Err(e) => Err(SwBufError::PlatformError(
|
||||||
|
Some(str.into()),
|
||||||
|
Some(Box::new(e)),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
75
src/lib.rs
75
src/lib.rs
|
|
@ -5,33 +5,35 @@
|
||||||
extern crate objc;
|
extern crate objc;
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
mod win32;
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
mod cg;
|
mod cg;
|
||||||
#[cfg(all(feature = "x11", any(target_os = "linux", target_os = "freebsd")))]
|
#[cfg(target_os = "redox")]
|
||||||
mod x11;
|
mod orbital;
|
||||||
#[cfg(all(feature = "wayland", any(target_os = "linux", target_os = "freebsd")))]
|
#[cfg(all(feature = "wayland", any(target_os = "linux", target_os = "freebsd")))]
|
||||||
mod wayland;
|
mod wayland;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
mod web;
|
mod web;
|
||||||
#[cfg(target_os = "redox")]
|
#[cfg(target_os = "windows")]
|
||||||
mod orbital;
|
mod win32;
|
||||||
|
#[cfg(all(feature = "x11", any(target_os = "linux", target_os = "freebsd")))]
|
||||||
|
mod x11;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
pub use error::SwBufError;
|
pub use error::SwBufError;
|
||||||
|
|
||||||
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle};
|
use raw_window_handle::{
|
||||||
|
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
|
||||||
|
};
|
||||||
|
|
||||||
/// An instance of this struct contains the platform-specific data that must be managed in order to
|
/// An instance of this struct contains the platform-specific data that must be managed in order to
|
||||||
/// write to a window on that platform.
|
/// write to a window on that platform.
|
||||||
pub struct GraphicsContext {
|
pub struct GraphicsContext {
|
||||||
/// The inner static dispatch object.
|
/// The inner static dispatch object.
|
||||||
///
|
///
|
||||||
/// This is boxed so that `GraphicsContext` is the same size on every platform, which should
|
/// This is boxed so that `GraphicsContext` is the same size on every platform, which should
|
||||||
/// hopefully prevent surprises.
|
/// hopefully prevent surprises.
|
||||||
graphics_context_impl: Box<Dispatch>
|
graphics_context_impl: Box<Dispatch>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A macro for creating the enum used to statically dispatch to the platform-specific implementation.
|
/// A macro for creating the enum used to statically dispatch to the platform-specific implementation.
|
||||||
|
|
@ -84,7 +86,10 @@ impl GraphicsContext {
|
||||||
///
|
///
|
||||||
/// - Ensure that the provided objects are valid to draw a 2D buffer to, and are valid for the
|
/// - Ensure that the provided objects are valid to draw a 2D buffer to, and are valid for the
|
||||||
/// lifetime of the GraphicsContext
|
/// lifetime of the GraphicsContext
|
||||||
pub unsafe fn new<W: HasRawWindowHandle, D: HasRawDisplayHandle>(window: &W, display: &D) -> Result<Self, SwBufError> {
|
pub unsafe fn new<W: HasRawWindowHandle, D: HasRawDisplayHandle>(
|
||||||
|
window: &W,
|
||||||
|
display: &D,
|
||||||
|
) -> Result<Self, SwBufError> {
|
||||||
Self::from_raw(window.raw_window_handle(), display.raw_display_handle())
|
Self::from_raw(window.raw_window_handle(), display.raw_display_handle())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,30 +99,54 @@ impl GraphicsContext {
|
||||||
///
|
///
|
||||||
/// - Ensure that the provided handles are valid to draw a 2D buffer to, and are valid for the
|
/// - Ensure that the provided handles are valid to draw a 2D buffer to, and are valid for the
|
||||||
/// lifetime of the GraphicsContext
|
/// lifetime of the GraphicsContext
|
||||||
pub unsafe fn from_raw(raw_window_handle: RawWindowHandle, raw_display_handle: RawDisplayHandle) -> Result<Self, SwBufError> {
|
pub unsafe fn from_raw(
|
||||||
|
raw_window_handle: RawWindowHandle,
|
||||||
|
raw_display_handle: RawDisplayHandle,
|
||||||
|
) -> Result<Self, SwBufError> {
|
||||||
let imple: Dispatch = match (raw_window_handle, raw_display_handle) {
|
let imple: Dispatch = match (raw_window_handle, raw_display_handle) {
|
||||||
#[cfg(all(feature = "x11", any(target_os = "linux", target_os = "freebsd")))]
|
#[cfg(all(feature = "x11", any(target_os = "linux", target_os = "freebsd")))]
|
||||||
(RawWindowHandle::Xlib(xlib_window_handle), RawDisplayHandle::Xlib(xlib_display_handle)) => Dispatch::X11(x11::X11Impl::new(xlib_window_handle, xlib_display_handle)?),
|
(
|
||||||
|
RawWindowHandle::Xlib(xlib_window_handle),
|
||||||
|
RawDisplayHandle::Xlib(xlib_display_handle),
|
||||||
|
) => Dispatch::X11(x11::X11Impl::new(xlib_window_handle, xlib_display_handle)?),
|
||||||
#[cfg(all(feature = "wayland", any(target_os = "linux", target_os = "freebsd")))]
|
#[cfg(all(feature = "wayland", any(target_os = "linux", target_os = "freebsd")))]
|
||||||
(RawWindowHandle::Wayland(wayland_window_handle), RawDisplayHandle::Wayland(wayland_display_handle)) => Dispatch::Wayland(wayland::WaylandImpl::new(wayland_window_handle, wayland_display_handle)?),
|
(
|
||||||
|
RawWindowHandle::Wayland(wayland_window_handle),
|
||||||
|
RawDisplayHandle::Wayland(wayland_display_handle),
|
||||||
|
) => Dispatch::Wayland(wayland::WaylandImpl::new(
|
||||||
|
wayland_window_handle,
|
||||||
|
wayland_display_handle,
|
||||||
|
)?),
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
(RawWindowHandle::Win32(win32_handle), _) => Dispatch::Win32(win32::Win32Impl::new(&win32_handle)?),
|
(RawWindowHandle::Win32(win32_handle), _) => {
|
||||||
|
Dispatch::Win32(win32::Win32Impl::new(&win32_handle)?)
|
||||||
|
}
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
(RawWindowHandle::AppKit(appkit_handle), _) => Dispatch::CG(cg::CGImpl::new(appkit_handle)?),
|
(RawWindowHandle::AppKit(appkit_handle), _) => {
|
||||||
|
Dispatch::CG(cg::CGImpl::new(appkit_handle)?)
|
||||||
|
}
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
(RawWindowHandle::Web(web_handle), _) => Dispatch::Web(web::WebImpl::new(web_handle)?),
|
(RawWindowHandle::Web(web_handle), _) => Dispatch::Web(web::WebImpl::new(web_handle)?),
|
||||||
#[cfg(target_os = "redox")]
|
#[cfg(target_os = "redox")]
|
||||||
(RawWindowHandle::Orbital(orbital_handle), _) => Dispatch::Orbital(orbital::OrbitalImpl::new(orbital_handle)?),
|
(RawWindowHandle::Orbital(orbital_handle), _) => {
|
||||||
(unimplemented_window_handle, unimplemented_display_handle) => return Err(SwBufError::UnsupportedPlatform {
|
Dispatch::Orbital(orbital::OrbitalImpl::new(orbital_handle)?)
|
||||||
human_readable_window_platform_name: window_handle_type_name(&unimplemented_window_handle),
|
}
|
||||||
human_readable_display_platform_name: display_handle_type_name(&unimplemented_display_handle),
|
(unimplemented_window_handle, unimplemented_display_handle) => {
|
||||||
window_handle: unimplemented_window_handle,
|
return Err(SwBufError::UnsupportedPlatform {
|
||||||
display_handle: unimplemented_display_handle
|
human_readable_window_platform_name: window_handle_type_name(
|
||||||
}),
|
&unimplemented_window_handle,
|
||||||
|
),
|
||||||
|
human_readable_display_platform_name: display_handle_type_name(
|
||||||
|
&unimplemented_display_handle,
|
||||||
|
),
|
||||||
|
window_handle: unimplemented_window_handle,
|
||||||
|
display_handle: unimplemented_display_handle,
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
graphics_context_impl: Box::new(imple)
|
graphics_context_impl: Box::new(imple),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
use raw_window_handle::OrbitalWindowHandle;
|
use raw_window_handle::OrbitalWindowHandle;
|
||||||
use std::{
|
use std::{cmp, slice, str};
|
||||||
cmp,
|
|
||||||
slice,
|
|
||||||
str,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::SwBufError;
|
use crate::SwBufError;
|
||||||
|
|
||||||
|
|
@ -19,12 +15,15 @@ impl OrbitalMap {
|
||||||
let size = pages * syscall::PAGE_SIZE;
|
let size = pages * syscall::PAGE_SIZE;
|
||||||
|
|
||||||
// Map window buffer
|
// Map window buffer
|
||||||
let address = syscall::fmap(fd, &syscall::Map {
|
let address = syscall::fmap(
|
||||||
offset: 0,
|
fd,
|
||||||
size,
|
&syscall::Map {
|
||||||
flags: syscall::PROT_READ | syscall::PROT_WRITE,
|
offset: 0,
|
||||||
address: 0,
|
size,
|
||||||
})?;
|
flags: syscall::PROT_READ | syscall::PROT_WRITE,
|
||||||
|
address: 0,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(Self { address, size })
|
Ok(Self { address, size })
|
||||||
}
|
}
|
||||||
|
|
@ -34,8 +33,7 @@ impl Drop for OrbitalMap {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Unmap window buffer on drop
|
// Unmap window buffer on drop
|
||||||
syscall::funmap(self.address, self.size)
|
syscall::funmap(self.address, self.size).expect("failed to unmap orbital window");
|
||||||
.expect("failed to unmap orbital window");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -71,15 +69,13 @@ impl OrbitalImpl {
|
||||||
|
|
||||||
{
|
{
|
||||||
// Map window buffer
|
// Map window buffer
|
||||||
let window_map = OrbitalMap::new(
|
let window_map = OrbitalMap::new(window_fd, window_width * window_height * 4)
|
||||||
window_fd,
|
.expect("failed to map orbital window");
|
||||||
window_width * window_height * 4
|
|
||||||
).expect("failed to map orbital window");
|
|
||||||
|
|
||||||
// Window buffer is u32 color data in 0xAABBGGRR format
|
// Window buffer is u32 color data in 0xAABBGGRR format
|
||||||
let window_data = slice::from_raw_parts_mut(
|
let window_data = slice::from_raw_parts_mut(
|
||||||
window_map.address as *mut u32,
|
window_map.address as *mut u32,
|
||||||
window_width * window_height
|
window_width * window_height,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Copy each line, cropping to fit
|
// Copy each line, cropping to fit
|
||||||
|
|
@ -90,9 +86,8 @@ impl OrbitalImpl {
|
||||||
for y in 0..min_height {
|
for y in 0..min_height {
|
||||||
let offset_buffer = y * width;
|
let offset_buffer = y * width;
|
||||||
let offset_data = y * window_width;
|
let offset_data = y * window_width;
|
||||||
window_data[offset_data..offset_data + min_width].copy_from_slice(
|
window_data[offset_data..offset_data + min_width]
|
||||||
&buffer[offset_buffer..offset_buffer + min_width]
|
.copy_from_slice(&buffer[offset_buffer..offset_buffer + min_width]);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Window buffer map is dropped here
|
// Window buffer map is dropped here
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,7 @@ impl WebImpl {
|
||||||
// `querySelector` only throws an error if the selector is invalid.
|
// `querySelector` only throws an error if the selector is invalid.
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
SwBufError::PlatformError(
|
SwBufError::PlatformError(Some("No canvas found with the given id".into()), None)
|
||||||
Some("No canvas found with the given id".into()),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
})?
|
})?
|
||||||
// We already made sure this was a canvas in `querySelector`.
|
// We already made sure this was a canvas in `querySelector`.
|
||||||
.unchecked_into();
|
.unchecked_into();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue