Add Fullscreen API compatibility for Safari (#2948)

This commit is contained in:
daxpedda 2023-07-11 00:34:02 +02:00 committed by GitHub
parent af26f01b95
commit 50b17a3907
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 19 deletions

View file

@ -14,6 +14,7 @@ And please only add new entries to the top of this list, right below the `# Unre
- On Web, implement `WindowEvent::Occluded`.
- On Web, fix touch location to be as accurate as mouse position.
- On Web, account for CSS `padding`, `border`, and `margin` when getting or setting the canvas position.
- On Web, add Fullscreen API compatibility for Safari.
# 0.29.0-beta.0

View file

@ -6,4 +6,7 @@ disallowed-methods = [
{ path = "web_sys::HtmlCanvasElement::set_height", reason = "Winit shouldn't touch the internal canvas size" },
{ path = "web_sys::Window::document", reason = "cache this to reduce calls to JS" },
{ path = "web_sys::Window::get_computed_style", reason = "cache this to reduce calls to JS" },
{ path = "web_sys::Element::request_fullscreen", reason = "Doesn't account for compatibility with Safari" },
{ path = "web_sys::Document::exit_fullscreen", reason = "Doesn't account for compatibility with Safari" },
{ path = "web_sys::Document::fullscreen_element", reason = "Doesn't account for compatibility with Safari" },
]

View file

@ -3,7 +3,7 @@ use super::event_handle::EventListenerHandle;
use super::intersection_handle::IntersectionObserverHandle;
use super::media_query_handle::MediaQueryListHandle;
use super::pointer::PointerHandler;
use super::{event, ButtonsState, ResizeScaleHandle};
use super::{event, fullscreen, ButtonsState, ResizeScaleHandle};
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
use crate::error::OsError as RootOE;
use crate::event::{Force, MouseButton, MouseScrollDelta};
@ -18,8 +18,7 @@ use std::sync::Arc;
use js_sys::Promise;
use smol_str::SmolStr;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
use wasm_bindgen::{closure::Closure, JsCast};
use wasm_bindgen_futures::JsFuture;
use web_sys::{
CssStyleDeclaration, Document, Event, FocusEvent, HtmlCanvasElement, KeyboardEvent, WheelEvent,
@ -504,27 +503,15 @@ impl Common {
handler(event);
if *wants_fullscreen.borrow() {
canvas
.request_fullscreen()
.expect("Failed to enter fullscreen");
fullscreen::request_fullscreen(&canvas).expect("Failed to enter fullscreen");
*wants_fullscreen.borrow_mut() = false;
}
})
}
pub fn request_fullscreen(&self) {
#[wasm_bindgen]
extern "C" {
type ElementExt;
#[wasm_bindgen(catch, method, js_name = requestFullscreen)]
fn request_fullscreen(this: &ElementExt) -> Result<JsValue, JsValue>;
}
let raw: &ElementExt = self.raw.unchecked_ref();
// This should return a `Promise`, but Safari v<16.4 is not up-to-date with the spec.
match raw.request_fullscreen() {
match fullscreen::request_fullscreen(&self.raw) {
Ok(value) if !value.is_undefined() => {
let promise: Promise = value.unchecked_into();
let wants_fullscreen = self.wants_fullscreen.clone();

View file

@ -0,0 +1,99 @@
use once_cell::unsync::OnceCell;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::{JsCast, JsValue};
use web_sys::{Document, Element, HtmlCanvasElement};
thread_local! {
static FULLSCREEN_API_SUPPORT: OnceCell<bool> = OnceCell::new();
}
fn canvas_has_fullscreen_api_support(canvas: &HtmlCanvasElement) -> bool {
FULLSCREEN_API_SUPPORT.with(|support| {
*support.get_or_init(|| {
#[wasm_bindgen]
extern "C" {
type CanvasFullScreenApiSupport;
#[wasm_bindgen(method, getter, js_name = requestFullscreen)]
fn has_request_fullscreen(this: &CanvasFullScreenApiSupport) -> JsValue;
}
let support: &CanvasFullScreenApiSupport = canvas.unchecked_ref();
!support.has_request_fullscreen().is_undefined()
})
})
}
fn document_has_fullscreen_api_support(document: &Document) -> bool {
FULLSCREEN_API_SUPPORT.with(|support| {
*support.get_or_init(|| {
#[wasm_bindgen]
extern "C" {
type DocumentFullScreenApiSupport;
#[wasm_bindgen(method, getter, js_name = exitFullscreen)]
fn has_exit_fullscreen(this: &DocumentFullScreenApiSupport) -> JsValue;
}
let support: &DocumentFullScreenApiSupport = document.unchecked_ref();
!support.has_exit_fullscreen().is_undefined()
})
})
}
pub fn request_fullscreen(canvas: &HtmlCanvasElement) -> Result<JsValue, JsValue> {
#[wasm_bindgen]
extern "C" {
type RequestFullscreen;
#[wasm_bindgen(catch, method, js_name = requestFullscreen)]
fn request_fullscreen(this: &RequestFullscreen) -> Result<JsValue, JsValue>;
#[wasm_bindgen(catch, method, js_name = webkitRequestFullscreen)]
fn webkit_request_fullscreen(this: &RequestFullscreen) -> Result<JsValue, JsValue>;
}
let element: &RequestFullscreen = canvas.unchecked_ref();
if canvas_has_fullscreen_api_support(canvas) {
element.request_fullscreen()
} else {
element.webkit_request_fullscreen()
}
}
pub fn exit_fullscreen(document: &Document) {
#[wasm_bindgen]
extern "C" {
type ExitFullscreen;
#[wasm_bindgen(method, js_name = webkitExitFullscreen)]
fn webkit_exit_fullscreen(this: &ExitFullscreen);
}
if document_has_fullscreen_api_support(document) {
#[allow(clippy::disallowed_methods)]
document.exit_fullscreen()
} else {
let document: &ExitFullscreen = document.unchecked_ref();
document.webkit_exit_fullscreen()
}
}
pub fn fullscreen_element(document: &Document) -> Option<Element> {
#[wasm_bindgen]
extern "C" {
type FullscreenElement;
#[wasm_bindgen(method, getter, js_name = webkitFullscreenElement)]
fn webkit_fullscreen_element(this: &FullscreenElement) -> Option<Element>;
}
if document_has_fullscreen_api_support(document) {
#[allow(clippy::disallowed_methods)]
document.fullscreen_element()
} else {
let document: &FullscreenElement = document.unchecked_ref();
document.webkit_fullscreen_element()
}
}

View file

@ -1,6 +1,7 @@
mod canvas;
pub mod event;
mod event_handle;
mod fullscreen;
mod intersection_handle;
mod media_query_handle;
mod pointer;
@ -26,7 +27,7 @@ pub fn throw(msg: &str) {
}
pub fn exit_fullscreen(document: &Document) {
document.exit_fullscreen();
fullscreen::exit_fullscreen(document);
}
pub struct PageTransitionEventHandle {
@ -115,7 +116,7 @@ pub fn set_canvas_style_property(raw: &HtmlCanvasElement, property: &str, value:
}
pub fn is_fullscreen(document: &Document, canvas: &HtmlCanvasElement) -> bool {
match document.fullscreen_element() {
match fullscreen::fullscreen_element(document) {
Some(elem) => {
let canvas: &Element = canvas;
canvas == &elem