use devela::_js_extern;
#[cfg(not(feature = "safe_lang"))]
#[cfg(feature = "unsafe_ffi")]
#[allow(unused_imports, reason = "not(windows)")]
use devela::{
_js_doc, Js, JsInstant, JsTextMetrics, JsTextMetricsFull, JsTimeout, TaskPoll, WebDocument,
WebEventKind, WebEventMouse, WebEventPointer, WebPermission, WebPermissionState, WebWindow,
WebWorker, WebWorkerError, WebWorkerJob, js_bool, js_int32, js_number, js_uint32, transmute,
};
#[cfg(not(feature = "safe_lang"))]
#[cfg(all(feature = "alloc", feature = "unsafe_ffi"))]
use devela::{String, Vec, vec_ as vec};
#[doc = crate::_tags!(web namespace)]
#[doc = crate::_doc_location!("sys/os/browser/web")]
#[derive(Clone, Copy, Debug)]
pub struct Web;
#[rustfmt::skip]
#[cfg(not(feature = "safe_lang"))]
#[cfg(all(feature = "unsafe_ffi", not(windows)))]
#[cfg_attr(nightly_doc, doc(cfg(all(feature = "unsafe_ffi", target_arch = "wasm32"))))]
impl Web {
#[doc = _js_doc!("Window")]
#[doc = _js_doc!("Screen")]
pub fn window() -> WebWindow { WebWindow }
#[doc = _js_doc!("Document")]
pub fn document() -> WebDocument { WebDocument }
}
#[rustfmt::skip]
#[cfg(not(feature = "safe_lang"))]
#[cfg(all(feature = "unsafe_ffi", not(windows)))]
#[cfg_attr(nightly_doc, doc(cfg(all(feature = "unsafe_ffi", target_arch = "wasm32"))))]
impl Web {
#[doc = _js_doc!("EventTarget", "addEventListener")]
pub fn event_add_listener(element: &str, event: WebEventKind, rust_fn: extern "C" fn()) {
unsafe {
event_add_listener(element.as_ptr(), element.len(),
event.as_str().as_ptr(), event.as_str().len(), rust_fn as usize);
}
}
#[doc = _js_doc!("EventTarget", "removeEventListener")]
pub fn event_remove_listener(element: &str, event: WebEventKind, rust_fn: extern "C" fn()) {
unsafe {
event_remove_listener(element.as_ptr(), element.len(),
event.as_str().as_ptr(), event.as_str().len(), rust_fn as usize);
}
}
#[doc = _js_doc!("EventTarget", "addEventListener")]
pub fn event_add_listener_js(element: &str, event: WebEventKind, js_fn_name: &str) {
unsafe {
event_add_listener_js(element.as_ptr(), element.len(),
event.as_str().as_ptr(), event.as_str().len(), js_fn_name.as_ptr(), js_fn_name.len());
}
}
#[doc = _js_doc!("EventTarget", "removeEventListener")]
pub fn event_remove_listener_js(element: &str, event: WebEventKind, js_fn_name: &str) {
unsafe {
event_remove_listener_js(element.as_ptr(), element.len(), event.as_str().as_ptr(),
event.as_str().len(), js_fn_name.as_ptr(), js_fn_name.len());
}
}
#[doc = _js_doc!("EventTarget", "addEventListener")]
pub fn event_add_listener_mouse(element: &str, event: WebEventKind,
callback: extern "C" fn(WebEventMouse)) {
unsafe {
event_add_listener_mouse(element.as_ptr(), element.len(),
event.as_str().as_ptr(), event.as_str().len(), callback as usize);
}
}
#[doc = _js_doc!("EventTarget", "addEventListener")]
pub fn event_add_listener_pointer(element: &str, event: WebEventKind,
callback: extern "C" fn(WebEventPointer)) {
unsafe {
event_add_listener_pointer(element.as_ptr(), element.len(),
event.as_str().as_ptr(), event.as_str().len(), callback as usize);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wasm_callback(callback_ptr: usize) {
let callback = callback_ptr as *const ();
let callback: extern "C" fn() = unsafe { transmute(callback) };
callback();
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wasm_callback_mouse(callback_ptr: usize, button: js_int32,
buttons: js_int32, x: js_number, y: js_number, etype: js_int32, timestamp: js_number) {
let callback = callback_ptr as *const ();
let callback: extern "C" fn(WebEventMouse) = unsafe { transmute(callback) };
let etype = WebEventKind::from_repr(etype as u8);
let timestamp = JsInstant::from_millis_f64(timestamp);
callback(WebEventMouse::new(x, y, button as u8, buttons as u8, etype, timestamp));
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wasm_callback_pointer(callback_ptr: usize, id: js_int32,
x: js_number, y: js_number, pressure: js_number, tilt_x: js_int32, tilt_y: js_int32,
twist: js_int32, etype: js_int32, timestamp: js_number) {
let callback = callback_ptr as *const ();
let callback: extern "C" fn(WebEventPointer) = unsafe { transmute(callback) };
let etype = WebEventKind::from_repr(etype as u8);
let timestamp = JsInstant::from_millis_f64(timestamp);
callback(WebEventPointer::new(x, y, pressure, id, tilt_x as i8, tilt_y as i8, twist as u16,
etype, timestamp));
}
}
_js_extern! {
[ module: "api_events" ]
unsafe fn "event_addListener" event_add_listener(element_ptr: *const u8,
element_len: usize, event_ptr: *const u8, event_len: usize, callback_ptr: usize);
unsafe fn "event_removeListener" event_remove_listener(element_ptr: *const u8,
element_len: usize, event_ptr: *const u8, event_len: usize, callback_ptr: usize);
unsafe fn "event_addListenerJs" event_add_listener_js(
element_ptr: *const u8, element_len: usize,
event_ptr: *const u8, event_len: usize, js_fn_ptr: *const u8, js_fn_len: usize
);
unsafe fn "event_removeListenerJs" event_remove_listener_js(
element_ptr: *const u8, element_len: usize,
event_ptr: *const u8, event_len: usize, js_fn_ptr: *const u8, js_fn_len: usize
);
unsafe fn "event_addListenerMouse" event_add_listener_mouse(element_ptr: *const u8,
element_len: usize, event_ptr: *const u8, event_len: usize, callback_ptr: usize);
unsafe fn "event_addListenerPointer" event_add_listener_pointer(element_ptr: *const u8,
element_len: usize, event_ptr: *const u8, event_len: usize, callback_ptr: usize);
}
#[rustfmt::skip]
#[cfg(not(feature = "safe_lang"))]
#[cfg(all(feature = "unsafe_ffi", not(windows)))]
#[cfg_attr(nightly_doc, doc(cfg(all(feature = "unsafe_ffi", target_arch = "wasm32"))))]
impl Web {
#[doc = _js_doc!("History", "back")]
pub fn history_back() { unsafe { history_back(); } }
#[doc = _js_doc!("History", "forward")]
pub fn history_forward() { unsafe { history_forward(); } }
#[doc = _js_doc!("History", "go")]
pub fn history_go(delta: js_int32) { unsafe { history_go(delta); } }
#[doc = _js_doc!("History", "pushState")]
pub fn history_push_state(state: &str, title: &str, url: &str) {
unsafe { history_push_state(state.as_ptr(), state.len(), title.as_ptr(), title.len(),
url.as_ptr(), url.len()); }
}
#[doc = _js_doc!("History", "replaceState")]
pub fn history_replace_state(state: &str, title: &str, url: &str) {
unsafe { history_replace_state(state.as_ptr(), state.len(), title.as_ptr(), title.len(),
url.as_ptr(), url.len()); }
}
#[doc = _js_doc!("Location", "reload")]
pub fn location_reload() { unsafe { location_reload(); } }
#[doc = _js_doc!("Location", "assign")]
pub fn location_assign(url: &str) { unsafe { location_assign(url.as_ptr(), url.len()); } }
#[doc = _js_doc!("Location", "replace")]
pub fn location_replace(url: &str) { unsafe { location_replace(url.as_ptr(), url.len()); } }
}
_js_extern! {
[ module: "api_history_location" ]
unsafe fn history_back();
unsafe fn history_forward();
unsafe fn history_go(delta: js_int32);
unsafe fn "history_pushState" history_push_state(state_ptr: *const u8, state_len: usize,
title_ptr: *const u8, title_len: usize, url_ptr: *const u8, url_len: usize);
unsafe fn "history_replaceState" history_replace_state(state_ptr: *const u8, state_len: usize,
title_ptr: *const u8, title_len: usize, url_ptr: *const u8, url_len: usize);
unsafe fn location_reload();
unsafe fn location_assign(url_ptr: *const u8, url_len: usize);
unsafe fn location_replace(url_ptr: *const u8, url_len: usize);
}
#[rustfmt::skip]
#[cfg(not(feature = "safe_lang"))]
#[cfg(all(feature = "unsafe_ffi", not(windows)))]
#[cfg_attr(nightly_doc, doc(cfg(all(feature = "unsafe_ffi", target_arch = "wasm32"))))]
impl Web {
#[doc = _js_doc!("Permissions", "query")]
pub fn permissions_query(permission: WebPermission) -> WebPermissionState {
unsafe { permissions_query(permission.as_str().as_ptr(), permission.as_str().len()) }
.into()
}
}
_js_extern! {
[ module: "api_permissions" ]
unsafe fn permissions_query(name_ptr: *const u8, name_len: usize) -> js_int32;
}
#[rustfmt::skip]
#[cfg(not(feature = "safe_lang"))]
#[cfg(all(feature = "unsafe_ffi", not(windows)))]
#[cfg_attr(nightly_doc, doc(cfg(all(feature = "unsafe_ffi", target_arch = "wasm32"))))]
impl Web {
pub fn set_canvas(selector: &str) { unsafe { set_canvas(selector.as_ptr(), selector.len()); } }
#[doc = _js_doc!(canvas "fillStyle")]
pub fn fill_style(r: u8, g: u8, b: u8) { fill_style(r, g, b); }
#[doc = _js_doc!(canvas "strokeStyle")]
pub fn stroke_style(r: u8, g: u8, b: u8) { stroke_style(r, g, b); }
#[doc = _js_doc!(canvas "fillRect")]
pub fn fill_rect(x: js_number, y: js_number, w: js_number, h: js_number)
{ fill_rect(x, y, w, h); }
#[doc = _js_doc!(canvas "strokeRect")]
pub fn stroke_rect(x: js_number, y: js_number, w: js_number, h: js_number)
{ stroke_rect(x, y, w, h); }
#[doc = _js_doc!(canvas "clearRect")]
pub fn clear_rect(x: js_number, y: js_number, w: js_number, h: js_number)
{ clear_rect(x, y, w, h); }
pub fn draw_line(x1: js_number, y1: js_number, x2: js_number, y2: js_number)
{ draw_line(x1, y1, x2, y2); }
pub fn draw_circle(x: js_number, y: js_number, radius: js_number)
{ draw_circle(x, y, radius); }
#[doc = _js_doc!(canvas "fillText")]
pub fn fill_text(text: &str, x: js_number, y: js_number) {
unsafe { fill_text(text.as_ptr(), text.len(), x, y); }
}
#[doc = _js_doc!(canvas "strokeText")]
pub fn stroke_text(text: &str, x: js_number, y: js_number) {
unsafe { stroke_text(text.as_ptr(), text.len(), x, y); }
}
#[doc = _js_doc!(canvas "measureText")]
pub fn measure_text(text: &str) -> JsTextMetrics {
let (mut metrics, ptr, len) = (JsTextMetrics::default(), text.as_ptr(), text.len());
unsafe { measure_text(ptr, len, &mut metrics as *mut JsTextMetrics); }
metrics
}
#[doc = _js_doc!(canvas "measureTextFull")]
pub fn measure_text_full(text: &str) -> JsTextMetricsFull {
let (mut metrics, ptr, len) = (JsTextMetricsFull::default(), text.as_ptr(), text.len());
unsafe { measure_text_full(ptr, len, &mut metrics as *mut JsTextMetricsFull); }
metrics
}
}
_js_extern! {
[ module: "api_canvas" ]
unsafe fn set_canvas(str_ptr: *const u8, str_len: usize);
safe fn "fillStyle" fill_style(r: u8, g: u8, b: u8);
safe fn "strokeStyle" stroke_style(r: u8, g: u8, b: u8);
safe fn "fillRect" fill_rect(x: js_number, y: js_number, w: js_number, h: js_number);
safe fn "strokeRect" stroke_rect(x: js_number, y: js_number, w: js_number, h: js_number);
safe fn "clearRect" clear_rect(x: js_number, y: js_number, w: js_number, h: js_number);
safe fn draw_line(x1: js_number, y1: js_number, x2: js_number, y2: js_number);
safe fn draw_circle(x: js_number, y: js_number, radius: js_number);
unsafe fn "fillText" fill_text(str_ptr: *const u8, str_len: usize, x: js_number, y: js_number);
unsafe fn "strokeText" stroke_text(str_ptr: *const u8, str_len: usize,
x: js_number, y: js_number);
unsafe fn "measureText" measure_text(text_ptr: *const u8, text_len: usize,
out_metrics: *mut JsTextMetrics);
unsafe fn "measureTextFull" measure_text_full(text_ptr: *const u8, text_len: usize,
out_metrics: *mut JsTextMetricsFull);
}
#[rustfmt::skip]
#[cfg(not(feature = "safe_lang"))]
#[cfg(all(feature = "unsafe_ffi", not(windows)))]
#[cfg_attr(nightly_doc, doc(cfg(all(feature = "unsafe_ffi", target_arch = "wasm32"))))]
impl Web {
#[doc = _js_doc!("Performance", "now")]
pub fn performance_now() -> JsInstant { JsInstant::from_millis_f64(performance_now()) }
#[doc = _js_doc!("Performance", "timeOrigin")]
pub fn performance_time_origin() -> JsInstant {
JsInstant::from_millis_f64(performance_time_origin()) }
#[doc = _js_doc!("Performance", "eventCounts")]
pub fn performance_event_count(event: WebEventKind) -> js_uint32 {
let name = event.as_str();
unsafe { performance_event_count(name.as_ptr(), name.len()) }
}
}
_js_extern! {
[ module: "api_performance" ]
safe fn "now" performance_now() -> js_number;
safe fn "timeOrigin" performance_time_origin() -> js_number;
unsafe fn "eventCounts" performance_event_count(event_ptr: *const u8, event_len: usize)
-> js_uint32;
}
#[rustfmt::skip]
#[cfg(not(feature = "safe_lang"))]
#[cfg(all(feature = "unsafe_ffi", not(windows)))]
#[cfg_attr(nightly_doc, doc(cfg(all(feature = "unsafe_ffi", target_arch = "wasm32"))))]
impl Web {
pub fn worker_spawn(script: &str) -> Result<WebWorker, WebWorkerError> {
let id = unsafe { worker_spawn(script.as_ptr(), script.len()) };
if id == 0 { Err(WebWorkerError::InvalidScript) } else { Ok(WebWorker { id }) }
}
pub fn worker_is_active(worker: WebWorker) -> js_bool { worker_is_active(worker.id()) }
pub fn worker_stop(worker: WebWorker) { worker_stop(worker.id()); }
pub fn worker_stop_all() { worker_stop_all(); }
pub fn worker_list_len() -> usize { worker_list_len() as usize }
#[cfg(feature = "alloc")]
#[cfg_attr(nightly_doc, doc(cfg(feature = "alloc")))]
pub fn worker_list() -> Vec<WebWorker> {
let len = worker_list_len() as usize;
let mut workers = vec![WebWorker::default(); len];
let count = Web::worker_list_buf(&mut workers);
workers.truncate(count);
workers
}
pub fn worker_list_buf(buffer: &mut [WebWorker]) -> usize {
let len = worker_list_len() as usize;
let count = len.min(buffer.len());
unsafe { worker_list(buffer.as_mut_ptr() as *mut js_uint32, count as js_uint32); }
count
}
pub fn worker_send_message(worker: WebWorker, msg: &str) {
unsafe { worker_send_message(worker.id(), msg.as_ptr(), msg.len()); }
}
pub fn worker_eval(worker: WebWorker, js_code: &str) -> WebWorkerJob {
let id = unsafe { worker_eval(worker.id(), js_code.as_ptr(), js_code.len()) };
WebWorkerJob { worker, id }
}
pub fn worker_poll(job: WebWorkerJob, buffer: &mut [u8])
-> TaskPoll<Result<usize, WebWorkerError>> {
if !job.worker().is_active() { return TaskPoll::Ready(Err(WebWorkerError::WorkerNotFound)); }
let written = unsafe { worker_poll(job.id(), buffer.as_mut_ptr(), buffer.len()) };
match written {
0 => TaskPoll::Pending,
js_uint32::MAX => TaskPoll::Ready(Err(WebWorkerError::JobNotFound)),
_ => TaskPoll::Ready(Ok(written as usize)),
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(nightly_doc, doc(cfg(feature = "alloc")))]
pub fn worker_poll_alloc(job: WebWorkerJob) -> TaskPoll<Result<String, WebWorkerError>> {
if !job.worker().is_active() { return TaskPoll::Ready(Err(WebWorkerError::WorkerNotFound)); }
let mut first_check = true;
let result = Js::read_string_capped(128, false, |ptr, cap| {
let res = unsafe { worker_poll(job.id(), ptr, cap as usize) as js_int32 };
if first_check {
first_check = false; if res == 0 { return 0; } else if res == -1 { return -1; } }
res
});
match result.as_str() {
"" => TaskPoll::Pending, _ => TaskPoll::Ready(Ok(result)),
}
}
pub fn worker_eval_cancel(job: WebWorkerJob) { worker_cancel_eval(job.id()); }
}
_js_extern! {
[module: "api_workers"]
unsafe fn worker_spawn(script_ptr: *const u8, script_len: usize) -> js_uint32;
safe fn worker_is_active(worker_id: js_uint32) -> js_bool;
safe fn worker_stop(worker_id: js_uint32);
safe fn worker_stop_all();
safe fn worker_list_len() -> js_uint32;
unsafe fn worker_list(worker_list_ptr: *mut js_uint32, len: js_uint32) -> js_uint32;
unsafe fn worker_send_message(worker_id: js_uint32, msg_ptr: *const u8, msg_len: usize);
unsafe fn worker_eval(worker_id: js_uint32, js_code_ptr: *const u8, js_code_len: usize)
-> js_uint32;
unsafe fn worker_poll(job_id: js_uint32, buffer_ptr: *mut u8, buffer_len: usize)
-> js_uint32;
safe fn worker_cancel_eval(job_id: js_uint32);
}