aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-12-09 09:52:34 -0800
committerGitHub <noreply@github.com>2016-12-09 09:52:34 -0800
commit8b69e73594647319e95bd0fd36c2addabcee1e5d (patch)
treefb8f23cab824af1e9731c3bc1acb754ee443c77b
parentc3c086e521b73d191d5de9239a6748691b0f96a3 (diff)
parent55f0e56224be03dcbd17d5cba1c45f8b0c6bb390 (diff)
downloadservo-8b69e73594647319e95bd0fd36c2addabcee1e5d.tar.gz
servo-8b69e73594647319e95bd0fd36c2addabcee1e5d.zip
Auto merge of #13489 - farodin91:fullscreen, r=jdm
Add support for fullscreen #10102 <!-- Please describe your changes on the following line: --> I'm start working on fullscreen support. @jdm Should be the entry_point in ScriptReflow a Option if fullscreen is enabled or point on the entry_node? For example the RootNode. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #10102 (github issue number if applicable). <!-- Either: --> - [x] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13489) <!-- Reviewable:end -->
-rw-r--r--Cargo.lock18
-rw-r--r--components/atoms/static_atoms.txt2
-rw-r--r--components/compositing/compositor.rs4
-rw-r--r--components/compositing/compositor_thread.rs5
-rw-r--r--components/compositing/windowing.rs2
-rw-r--r--components/constellation/constellation.rs3
-rw-r--r--components/profile/time.rs2
-rw-r--r--components/profile_traits/time.rs2
-rw-r--r--components/script/dom/document.rs141
-rw-r--r--components/script/dom/element.rs149
-rw-r--r--components/script/dom/htmliframeelement.rs7
-rw-r--r--components/script/dom/webidls/Document.webidl12
-rw-r--r--components/script/dom/webidls/Element.webidl5
-rw-r--r--components/script/dom/webidls/HTMLIFrameElement.webidl2
-rw-r--r--components/script/layout_wrapper.rs1
-rw-r--r--components/script/script_runtime.rs4
-rw-r--r--components/script/script_thread.rs4
-rw-r--r--components/script_traits/script_msg.rs2
-rw-r--r--components/style/element_state.rs2
-rw-r--r--components/style/gecko/selector_parser.rs4
-rw-r--r--components/style/gecko/wrapper.rs1
-rw-r--r--components/style/servo/selector_parser.rs4
-rw-r--r--ports/cef/window.rs3
-rw-r--r--ports/glutin/window.rs9
-rw-r--r--resources/user-agent.css22
-rw-r--r--tests/wpt/include.ini2
-rw-r--r--tests/wpt/metadata/html/dom/interfaces.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html.ini3
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json6
-rw-r--r--tests/wpt/mozilla/tests/mozilla/fullscreen-remove-single.html23
-rw-r--r--tests/wpt/web-platform-tests/fullscreen/api/blank.html10
-rw-r--r--tests/wpt/web-platform-tests/fullscreen/api/document-fullscreen-enabled.html18
-rw-r--r--tests/wpt/web-platform-tests/fullscreen/api/document-onfullscreenerror.html9
33 files changed, 454 insertions, 30 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3e90dbb14e4..679a7b7fe2d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1075,7 +1075,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "html5ever-atoms 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mac 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"phf 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1088,7 +1088,7 @@ dependencies = [
[[package]]
name = "html5ever-atoms"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1272,7 +1272,7 @@ dependencies = [
"gfx_traits 0.0.1",
"heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "html5ever-atoms 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2189,7 +2189,7 @@ dependencies = [
"heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"html5ever 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "html5ever-atoms 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper_serde 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2247,7 +2247,7 @@ dependencies = [
"gfx_traits 0.0.1",
"heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "html5ever-atoms 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2598,7 +2598,7 @@ dependencies = [
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "html5ever-atoms 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2635,7 +2635,7 @@ dependencies = [
"app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "html5ever-atoms 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3192,7 +3192,7 @@ name = "xml5ever"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "html5ever-atoms 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mac 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"phf 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3290,7 +3290,7 @@ dependencies = [
"checksum heartbeats-simple-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53c4b67617665d7f4172f381f9843c1bec6a4fccc9a9226529e5b1be40dc1301"
"checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58"
"checksum html5ever 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "45815593feb142cf01121b9f413d8630c9902192d160e494a579c50628eef498"
-"checksum html5ever-atoms 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "daefa106438c66af58309c84842b5db1df2733fe35849f39adde6fdf63583d40"
+"checksum html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fd3fc831590ee7fcf693c673e4e3cbe14fbda44dc0f26d9bdc79cfc9f551dc05"
"checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae"
"checksum hyper 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "edd47c66782933e546a32ae89ca3c49263b2ba9bc29f3a0d5c52fff48e0ac67c"
"checksum hyper_serde 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "572d2168173019de312a050a24f2ad33ac2ac7895a2139fbf21ee6b6f470a24e"
diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt
index 153c0962eeb..2ac84aa2f4e 100644
--- a/components/atoms/static_atoms.txt
+++ b/components/atoms/static_atoms.txt
@@ -78,3 +78,5 @@ statechange
controllerchange
fetch
characteristicvaluechanged
+fullscreenchange
+fullscreenerror
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index 1fc3a5b27f5..a721c2b19c8 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -633,6 +633,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
func();
}
+ (Msg::SetFullscreenState(state), ShutdownState::NotShuttingDown) => {
+ self.window.set_fullscreen_state(state);
+ }
+
// When we are shutting_down, we need to avoid performing operations
// such as Paint that may crash because we have begun tearing down
// the rest of our resources.
diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs
index 0a7962c7917..8a78a7e8882 100644
--- a/components/compositing/compositor_thread.rs
+++ b/components/compositing/compositor_thread.rs
@@ -128,7 +128,9 @@ pub enum Msg {
/// Runs a closure in the compositor thread.
/// It's used to dispatch functions from webrender to the main thread's event loop.
/// Required to allow WGL GLContext sharing in Windows.
- Dispatch(Box<Fn() + Send>)
+ Dispatch(Box<Fn() + Send>),
+ /// Enter or exit fullscreen
+ SetFullscreenState(bool),
}
impl Debug for Msg {
@@ -161,6 +163,7 @@ impl Debug for Msg {
Msg::PipelineExited(..) => write!(f, "PipelineExited"),
Msg::NewScrollFrameReady(..) => write!(f, "NewScrollFrameReady"),
Msg::Dispatch(..) => write!(f, "Dispatch"),
+ Msg::SetFullscreenState(..) => write!(f, "SetFullscreenState"),
}
}
}
diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs
index d905b53a39f..33eed7630cc 100644
--- a/components/compositing/windowing.rs
+++ b/components/compositing/windowing.rs
@@ -119,6 +119,8 @@ pub trait WindowMethods {
fn set_inner_size(&self, size: Size2D<u32>);
/// Set the window position
fn set_position(&self, point: Point2D<i32>);
+ /// Set fullscreen state
+ fn set_fullscreen_state(&self, state: bool);
/// Sets the page title for the current page.
fn set_page_title(&self, title: Option<String>);
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index c64e3ee3811..c34f9b1597c 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -1090,6 +1090,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
FromScriptMsg::BroadcastStorageEvent(pipeline_id, storage, url, key, old_value, new_value) => {
self.handle_broadcast_storage_event(pipeline_id, storage, url, key, old_value, new_value);
}
+ FromScriptMsg::SetFullscreenState(state) => {
+ self.compositor_proxy.send(ToCompositorMsg::SetFullscreenState(state));
+ }
}
}
diff --git a/components/profile/time.rs b/components/profile/time.rs
index 62f85b362d2..648c31f83d6 100644
--- a/components/profile/time.rs
+++ b/components/profile/time.rs
@@ -150,6 +150,8 @@ impl Formattable for ProfilerCategory {
ProfilerCategory::ScriptWebSocketEvent => "Script Web Socket Event",
ProfilerCategory::ScriptWorkerEvent => "Script Worker Event",
ProfilerCategory::ScriptServiceWorkerEvent => "Script Service Worker Event",
+ ProfilerCategory::ScriptEnterFullscreen => "Script Enter Fullscreen",
+ ProfilerCategory::ScriptExitFullscreen => "Script Exit Fullscreen",
ProfilerCategory::ApplicationHeartbeat => "Application Heartbeat",
};
format!("{}{}", padding, name)
diff --git a/components/profile_traits/time.rs b/components/profile_traits/time.rs
index c8cf4913f1e..ae114f98bc0 100644
--- a/components/profile_traits/time.rs
+++ b/components/profile_traits/time.rs
@@ -86,6 +86,8 @@ pub enum ProfilerCategory {
ScriptWorkerEvent = 0x74,
ScriptServiceWorkerEvent = 0x75,
ScriptParseXML = 0x76,
+ ScriptEnterFullscreen = 0x77,
+ ScriptExitFullscreen = 0x78,
ApplicationHeartbeat = 0x90,
}
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index d0dbe75ebd3..0e16ca16f81 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -27,7 +27,7 @@ use dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, Nod
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root};
use dom::bindings::js::RootedReference;
use dom::bindings::num::Finite;
-use dom::bindings::refcounted::Trusted;
+use dom::bindings::refcounted::{Trusted, TrustedPromise};
use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::str::{DOMString, USVString};
use dom::bindings::xmlname::{namespace_from_domstring, validate_and_extract, xml_name_type};
@@ -39,7 +39,7 @@ use dom::customevent::CustomEvent;
use dom::documentfragment::DocumentFragment;
use dom::documenttype::DocumentType;
use dom::domimplementation::DOMImplementation;
-use dom::element::{Element, ElementCreator};
+use dom::element::{Element, ElementCreator, ElementPerformFullscreenEnter, ElementPerformFullscreenExit};
use dom::errorevent::ErrorEvent;
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventdispatcher::EventStatus;
@@ -74,6 +74,7 @@ use dom::pagetransitionevent::PageTransitionEvent;
use dom::popstateevent::PopStateEvent;
use dom::processinginstruction::ProcessingInstruction;
use dom::progressevent::ProgressEvent;
+use dom::promise::Promise;
use dom::range::Range;
use dom::servoparser::ServoParser;
use dom::storageevent::StorageEvent;
@@ -105,6 +106,7 @@ use net_traits::response::HttpsState;
use num_traits::ToPrimitive;
use origin::Origin;
use script_layout_interface::message::{Msg, ReflowQueryType};
+use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory};
use script_thread::{MainThreadScriptMsg, Runnable};
use script_traits::{AnimationState, CompositorEvent, MouseButton, MouseEventType, MozBrowserEvent};
use script_traits::{ScriptMsg as ConstellationMsg, TouchpadPressurePhase};
@@ -290,6 +292,8 @@ pub struct Document {
///
/// See also: https://github.com/servo/servo/issues/10110
dom_count: Cell<u32>,
+ /// Entry node for fullscreen.
+ fullscreen_element: MutNullableHeap<JS<Element>>,
}
#[derive(JSTraceable, HeapSizeOf)]
@@ -1907,6 +1911,7 @@ impl Document {
last_click_info: DOMRefCell::new(None),
ignore_destructive_writes_counter: Default::default(),
dom_count: Cell::new(1),
+ fullscreen_element: MutNullableHeap::new(None),
}
}
@@ -2092,6 +2097,110 @@ impl Document {
self.ignore_destructive_writes_counter.set(
self.ignore_destructive_writes_counter.get() - 1);
}
+
+ // https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen
+ #[allow(unrooted_must_root)]
+ pub fn enter_fullscreen(&self, pending: &Element) -> Rc<Promise> {
+ // Step 1
+ let promise = Promise::new(self.global().r());
+ let mut error = false;
+
+ // Step 4
+ // check namespace
+ match *pending.namespace() {
+ ns!(mathml) => {
+ if pending.local_name().as_ref() != "math" {
+ error = true;
+ }
+ }
+ ns!(svg) => {
+ if pending.local_name().as_ref() != "svg" {
+ error = true;
+ }
+ }
+ ns!(html) => (),
+ _ => error = true,
+ }
+ // fullscreen element ready check
+ if !pending.fullscreen_element_ready_check() {
+ error = true;
+ }
+ // TODO fullscreen is supported
+ // TODO This algorithm is allowed to request fullscreen.
+
+ // Step 5 Parallel start
+
+ let window = self.window();
+ // Step 6
+ if !error {
+ let event = ConstellationMsg::SetFullscreenState(true);
+ window.upcast::<GlobalScope>().constellation_chan().send(event).unwrap();
+ }
+
+ // Step 7
+ let trusted_pending = Trusted::new(pending);
+ let trusted_promise = TrustedPromise::new(promise.clone());
+ let handler = ElementPerformFullscreenEnter::new(trusted_pending, trusted_promise, error);
+ let script_msg = CommonScriptMsg::RunnableMsg(ScriptThreadEventCategory::EnterFullscreen, handler);
+ let msg = MainThreadScriptMsg::Common(script_msg);
+ window.main_thread_script_chan().send(msg).unwrap();
+
+ promise
+ }
+
+ // https://fullscreen.spec.whatwg.org/#exit-fullscreen
+ #[allow(unrooted_must_root)]
+ pub fn exit_fullscreen(&self) -> Rc<Promise> {
+ let global = self.global();
+ // Step 1
+ let promise = Promise::new(global.r());
+ // Step 2
+ if self.fullscreen_element.get().is_none() {
+ promise.reject_error(global.get_cx(), Error::Type(String::from("fullscreen is null")));
+ return promise
+ }
+ // TODO Step 3-6
+ let element = self.fullscreen_element.get().unwrap();
+
+ // Step 7 Parallel start
+
+ let window = self.window();
+ // Step 8
+ let event = ConstellationMsg::SetFullscreenState(false);
+ window.upcast::<GlobalScope>().constellation_chan().send(event).unwrap();
+
+ // Step 9
+ let trusted_element = Trusted::new(element.r());
+ let trusted_promise = TrustedPromise::new(promise.clone());
+ let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
+ let script_msg = CommonScriptMsg::RunnableMsg(ScriptThreadEventCategory::ExitFullscreen, handler);
+ let msg = MainThreadScriptMsg::Common(script_msg);
+ window.main_thread_script_chan().send(msg).unwrap();
+
+ promise
+ }
+
+ pub fn set_fullscreen_element(&self, element: Option<&Element>) {
+ self.fullscreen_element.set(element);
+ }
+
+ pub fn get_allow_fullscreen(&self) -> bool {
+ // https://html.spec.whatwg.org/multipage/#allowed-to-use
+ match self.browsing_context() {
+ // Step 1
+ None => false,
+ Some(_) => {
+ // Step 2
+ let window = self.window();
+ if window.is_top_level() {
+ true
+ } else {
+ // Step 3
+ window.GetFrameElement().map_or(false, |el| el.has_attribute(&local_name!("allowfullscreen")))
+ }
+ }
+ }
+ }
}
@@ -3109,6 +3218,34 @@ impl DocumentMethods for Document {
// https://html.spec.whatwg.org/multipage/#documentandelementeventhandlers
document_and_element_event_handlers!();
+
+ // https://fullscreen.spec.whatwg.org/#handler-document-onfullscreenerror
+ event_handler!(fullscreenerror, GetOnfullscreenerror, SetOnfullscreenerror);
+
+ // https://fullscreen.spec.whatwg.org/#handler-document-onfullscreenchange
+ event_handler!(fullscreenchange, GetOnfullscreenchange, SetOnfullscreenchange);
+
+ // https://fullscreen.spec.whatwg.org/#dom-document-fullscreenenabled
+ fn FullscreenEnabled(&self) -> bool {
+ self.get_allow_fullscreen()
+ }
+
+ // https://fullscreen.spec.whatwg.org/#dom-document-fullscreen
+ fn Fullscreen(&self) -> bool {
+ self.fullscreen_element.get().is_some()
+ }
+
+ // https://fullscreen.spec.whatwg.org/#dom-document-fullscreenelement
+ fn GetFullscreenElement(&self) -> Option<Root<Element>> {
+ // TODO ShadowRoot
+ self.fullscreen_element.get()
+ }
+
+ #[allow(unrooted_must_root)]
+ // https://fullscreen.spec.whatwg.org/#dom-document-exitfullscreen
+ fn ExitFullscreen(&self) -> Rc<Promise> {
+ self.exit_fullscreen()
+ }
}
fn update_with_current_time_ms(marker: &Cell<u64>) {
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 6df2122e7b3..d9831d79a69 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -24,6 +24,8 @@ use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap};
use dom::bindings::js::{Root, RootedReference};
+use dom::bindings::refcounted::{Trusted, TrustedPromise};
+use dom::bindings::reflector::DomObject;
use dom::bindings::str::DOMString;
use dom::bindings::xmlname::{namespace_from_domstring, validate_and_extract, xml_name_type};
use dom::bindings::xmlname::XMLName::InvalidXMLName;
@@ -35,6 +37,7 @@ use dom::domrect::DOMRect;
use dom::domrectlist::DOMRectList;
use dom::domtokenlist::DOMTokenList;
use dom::event::Event;
+use dom::eventtarget::EventTarget;
use dom::htmlanchorelement::HTMLAnchorElement;
use dom::htmlbodyelement::{HTMLBodyElement, HTMLBodyElementLayoutHelpers};
use dom::htmlbuttonelement::HTMLButtonElement;
@@ -62,18 +65,23 @@ use dom::node::{CLICK_IN_PROGRESS, ChildrenMutation, LayoutNodeHelpers, Node};
use dom::node::{NodeDamage, SEQUENTIALLY_FOCUSABLE, UnbindContext};
use dom::node::{document_from_node, window_from_node};
use dom::nodelist::NodeList;
+use dom::promise::Promise;
use dom::servoparser::ServoParser;
use dom::text::Text;
use dom::validation::Validatable;
use dom::virtualmethods::{VirtualMethods, vtable_for};
+use dom::window::ReflowReason;
use html5ever::serialize;
use html5ever::serialize::SerializeOpts;
use html5ever::serialize::TraversalScope;
use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
use html5ever::tree_builder::{LimitedQuirks, NoQuirks, Quirks};
use html5ever_atoms::{Prefix, LocalName, Namespace, QualName};
+use js::jsapi::{HandleValue, JSAutoCompartment};
use parking_lot::RwLock;
use ref_filter_map::ref_filter_map;
+use script_layout_interface::message::ReflowQueryType;
+use script_thread::Runnable;
use selectors::matching::{ElementFlags, MatchingReason, matches};
use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
use selectors::parser::{AttrSelector, NamespaceConstraint};
@@ -84,9 +92,11 @@ use std::cell::{Cell, Ref};
use std::convert::TryFrom;
use std::default::Default;
use std::fmt;
+use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
+use style::context::ReflowGoal;
use style::dom::TRestyleDamage;
use style::element_state::*;
use style::matching::{common_style_affecting_attributes, rare_style_affecting_attributes};
@@ -1300,6 +1310,15 @@ impl Element {
}
}
}
+
+ // https://fullscreen.spec.whatwg.org/#fullscreen-element-ready-check
+ pub fn fullscreen_element_ready_check(&self) -> bool {
+ if !self.is_connected() {
+ return false
+ }
+ let document = document_from_node(self);
+ document.get_allow_fullscreen()
+ }
}
impl ElementMethods for Element {
@@ -2056,6 +2075,13 @@ impl ElementMethods for Element {
None => return Err(Error::NotSupported)
}
}
+
+ // https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen
+ #[allow(unrooted_must_root)]
+ fn RequestFullscreen(&self) -> Rc<Promise> {
+ let doc = document_from_node(self);
+ doc.enter_fullscreen(self)
+ }
}
pub fn fragment_affecting_attributes() -> [LocalName; 3] {
@@ -2167,6 +2193,10 @@ impl VirtualMethods for Element {
}
let doc = document_from_node(self);
+ let fullscreen = doc.GetFullscreenElement();
+ if fullscreen.r() == Some(self) {
+ doc.exit_fullscreen();
+ }
if let Some(ref value) = *self.id_attribute.borrow() {
doc.unregister_named_element(self, value.clone());
}
@@ -2307,6 +2337,7 @@ impl<'a> ::selectors::Element for Root<Element> {
NonTSPseudoClass::Active |
NonTSPseudoClass::Focus |
+ NonTSPseudoClass::Fullscreen |
NonTSPseudoClass::Hover |
NonTSPseudoClass::Enabled |
NonTSPseudoClass::Disabled |
@@ -2582,7 +2613,22 @@ impl Element {
}
pub fn set_target_state(&self, value: bool) {
- self.set_state(IN_TARGET_STATE, value)
+ self.set_state(IN_TARGET_STATE, value)
+ }
+
+ pub fn fullscreen_state(&self) -> bool {
+ self.state.get().contains(IN_FULLSCREEN_STATE)
+ }
+
+ pub fn set_fullscreen_state(&self, value: bool) {
+ self.set_state(IN_FULLSCREEN_STATE, value)
+ }
+
+ /// https://dom.spec.whatwg.org/#connected
+ pub fn is_connected(&self) -> bool {
+ let node = self.upcast::<Node>();
+ let root = node.GetRootNode();
+ root.is::<Document>()
}
}
@@ -2713,3 +2759,104 @@ impl TagName {
*self.ptr.borrow_mut() = None;
}
}
+
+pub struct ElementPerformFullscreenEnter {
+ element: Trusted<Element>,
+ promise: TrustedPromise,
+ error: bool,
+}
+
+impl ElementPerformFullscreenEnter {
+ pub fn new(element: Trusted<Element>, promise: TrustedPromise, error: bool) -> Box<ElementPerformFullscreenEnter> {
+ box ElementPerformFullscreenEnter {
+ element: element,
+ promise: promise,
+ error: error,
+ }
+ }
+}
+
+impl Runnable for ElementPerformFullscreenEnter {
+ fn name(&self) -> &'static str { "ElementPerformFullscreenEnter" }
+
+ #[allow(unrooted_must_root)]
+ fn handler(self: Box<ElementPerformFullscreenEnter>) {
+ let element = self.element.root();
+ let document = document_from_node(element.r());
+
+ // Step 7.1
+ if self.error || !element.fullscreen_element_ready_check() {
+ // JSAutoCompartment needs to be manually made.
+ // Otherwise, Servo will crash.
+ let promise = self.promise.root();
+ let promise_cx = promise.global().get_cx();
+ let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
+ document.upcast::<EventTarget>().fire_event(atom!("fullscreenerror"));
+ promise.reject_error(promise.global().get_cx(), Error::Type(String::from("fullscreen is not connected")));
+ return
+ }
+
+ // TODO Step 7.2-4
+ // Step 7.5
+ element.set_fullscreen_state(true);
+ document.set_fullscreen_element(Some(&element));
+ document.window().reflow(ReflowGoal::ForDisplay,
+ ReflowQueryType::NoQuery,
+ ReflowReason::ElementStateChanged);
+
+ // Step 7.6
+ document.upcast::<EventTarget>().fire_event(atom!("fullscreenchange"));
+
+ // Step 7.7
+ // JSAutoCompartment needs to be manually made.
+ // Otherwise, Servo will crash.
+ let promise = self.promise.root();
+ let promise_cx = promise.global().get_cx();
+ let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
+ promise.resolve(promise.global().get_cx(), HandleValue::undefined());
+ }
+}
+
+pub struct ElementPerformFullscreenExit {
+ element: Trusted<Element>,
+ promise: TrustedPromise,
+}
+
+impl ElementPerformFullscreenExit {
+ pub fn new(element: Trusted<Element>, promise: TrustedPromise) -> Box<ElementPerformFullscreenExit> {
+ box ElementPerformFullscreenExit {
+ element: element,
+ promise: promise,
+ }
+ }
+}
+
+impl Runnable for ElementPerformFullscreenExit {
+ fn name(&self) -> &'static str { "ElementPerformFullscreenExit" }
+
+ #[allow(unrooted_must_root)]
+ fn handler(self: Box<ElementPerformFullscreenExit>) {
+ let element = self.element.root();
+ let document = document_from_node(element.r());
+ // TODO Step 9.1-5
+ // Step 9.6
+ element.set_fullscreen_state(false);
+
+ document.window().reflow(ReflowGoal::ForDisplay,
+ ReflowQueryType::NoQuery,
+ ReflowReason::ElementStateChanged);
+
+ document.set_fullscreen_element(None);
+
+ // Step 9.8
+ document.upcast::<EventTarget>().fire_event(atom!("fullscreenchange"));
+
+ // Step 9.10
+ let promise = self.promise.root();
+ // JSAutoCompartment needs to be manually made.
+ // Otherwise, Servo will crash.
+ let promise_cx = promise.global().get_cx();
+ let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
+ promise.resolve(promise.global().get_cx(), HandleValue::undefined());
+ }
+}
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index 0f55f3c6be3..44323e1c1ef 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -15,7 +15,7 @@ use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementVisib
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserShowModalPromptEventDetail;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
-use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
+use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::inheritance::Castable;
@@ -544,6 +544,11 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
element.set_bool_attribute(&local_name!("mozbrowser"), value);
}
+ // https://html.spec.whatwg.org/multipage/#attr-iframe-allowfullscreen
+ make_bool_getter!(AllowFullscreen, "allowfullscreen");
+ // https://html.spec.whatwg.org/multipage/#attr-iframe-allowfullscreen
+ make_bool_setter!(SetAllowFullscreen, "allowfullscreen");
+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goBack
fn GoBack(&self) -> ErrorResult {
Navigate(self, TraversalDirection::Back(1))
diff --git a/components/script/dom/webidls/Document.webidl b/components/script/dom/webidls/Document.webidl
index 1e8725d8b86..4955bf6e956 100644
--- a/components/script/dom/webidls/Document.webidl
+++ b/components/script/dom/webidls/Document.webidl
@@ -190,3 +190,15 @@ partial interface Document {
partial interface Document {
[SameObject] readonly attribute StyleSheetList styleSheets;
};
+
+// https://fullscreen.spec.whatwg.org/#api
+partial interface Document {
+ [LenientSetter] readonly attribute boolean fullscreenEnabled;
+ [LenientSetter] readonly attribute Element? fullscreenElement;
+ [LenientSetter] readonly attribute boolean fullscreen; // historical
+
+ Promise<void> exitFullscreen();
+
+ attribute EventHandler onfullscreenchange;
+ attribute EventHandler onfullscreenerror;
+};
diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl
index 4e79166e945..61a54e180d0 100644
--- a/components/script/dom/webidls/Element.webidl
+++ b/components/script/dom/webidls/Element.webidl
@@ -110,6 +110,11 @@ partial interface Element {
attribute DOMString outerHTML;
};
+// https://fullscreen.spec.whatwg.org/#api
+partial interface Element {
+ Promise<void> requestFullscreen();
+};
+
Element implements ChildNode;
Element implements NonDocumentTypeChildNode;
Element implements ParentNode;
diff --git a/components/script/dom/webidls/HTMLIFrameElement.webidl b/components/script/dom/webidls/HTMLIFrameElement.webidl
index 330453d9f8c..f02c7c35a1b 100644
--- a/components/script/dom/webidls/HTMLIFrameElement.webidl
+++ b/components/script/dom/webidls/HTMLIFrameElement.webidl
@@ -13,7 +13,7 @@ interface HTMLIFrameElement : HTMLElement {
[SameObject, PutForwards=value]
readonly attribute DOMTokenList sandbox;
// attribute boolean seamless;
- // attribute boolean allowFullscreen;
+ attribute boolean allowFullscreen;
attribute DOMString width;
attribute DOMString height;
readonly attribute Document? contentDocument;
diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs
index a6d4815090f..338edc19730 100644
--- a/components/script/layout_wrapper.rs
+++ b/components/script/layout_wrapper.rs
@@ -666,6 +666,7 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
NonTSPseudoClass::Active |
NonTSPseudoClass::Focus |
+ NonTSPseudoClass::Fullscreen |
NonTSPseudoClass::Hover |
NonTSPseudoClass::Enabled |
NonTSPseudoClass::Disabled |
diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs
index f65b145c4ec..00e7d3a198e 100644
--- a/components/script/script_runtime.rs
+++ b/components/script/script_runtime.rs
@@ -76,7 +76,9 @@ pub enum ScriptThreadEventCategory {
UpdateReplacedElement,
WebSocketEvent,
WorkerEvent,
- ServiceWorkerEvent
+ ServiceWorkerEvent,
+ EnterFullscreen,
+ ExitFullscreen,
}
/// An interface for receiving ScriptMsg values in an event loop. Used for synchronous DOM
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index ad8c3d09e57..f55d9279138 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -946,7 +946,9 @@ impl ScriptThread {
ScriptThreadEventCategory::TimerEvent => ProfilerCategory::ScriptTimerEvent,
ScriptThreadEventCategory::WebSocketEvent => ProfilerCategory::ScriptWebSocketEvent,
ScriptThreadEventCategory::WorkerEvent => ProfilerCategory::ScriptWorkerEvent,
- ScriptThreadEventCategory::ServiceWorkerEvent => ProfilerCategory::ScriptServiceWorkerEvent
+ ScriptThreadEventCategory::ServiceWorkerEvent => ProfilerCategory::ScriptServiceWorkerEvent,
+ ScriptThreadEventCategory::EnterFullscreen => ProfilerCategory::ScriptEnterFullscreen,
+ ScriptThreadEventCategory::ExitFullscreen => ProfilerCategory::ScriptExitFullscreen,
};
profile(profiler_cat, None, self.time_profiler_chan.clone(), f)
} else {
diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs
index e91a034fec9..80dbc3f4165 100644
--- a/components/script_traits/script_msg.rs
+++ b/components/script_traits/script_msg.rs
@@ -145,6 +145,8 @@ pub enum ScriptMsg {
ForwardDOMMessage(DOMMessage, ServoUrl),
/// Store the data required to activate a service worker for the given scope
RegisterServiceWorker(ScopeThings, ServoUrl),
+ /// Enter or exit fullscreen
+ SetFullscreenState(bool),
/// Requests that the compositor shut down.
Exit
}
diff --git a/components/style/element_state.rs b/components/style/element_state.rs
index f394a7003ef..ef6e9704170 100644
--- a/components/style/element_state.rs
+++ b/components/style/element_state.rs
@@ -35,5 +35,7 @@ bitflags! {
const IN_PLACEHOLDER_SHOWN_STATE = 0x0100,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-target"]
const IN_TARGET_STATE = 0x0200,
+ #[doc = "https://fullscreen.spec.whatwg.org/#%3Afullscreen-pseudo-class"]
+ const IN_FULLSCREEN_STATE = 0x0400,
}
}
diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs
index 608295af954..d9fdf6a4431 100644
--- a/components/style/gecko/selector_parser.rs
+++ b/components/style/gecko/selector_parser.rs
@@ -109,6 +109,7 @@ pub enum NonTSPseudoClass {
Visited,
Active,
Focus,
+ Fullscreen,
Hover,
Enabled,
Disabled,
@@ -127,6 +128,7 @@ impl ToCss for NonTSPseudoClass {
Visited => ":visited",
Active => ":active",
Focus => ":focus",
+ Fullscreen => ":fullscreen",
Hover => ":hover",
Enabled => ":enabled",
Disabled => ":disabled",
@@ -145,6 +147,7 @@ impl NonTSPseudoClass {
match *self {
Active => IN_ACTIVE_STATE,
Focus => IN_FOCUS_STATE,
+ Fullscreen => IN_FULLSCREEN_STATE,
Hover => IN_HOVER_STATE,
Enabled => IN_ENABLED_STATE,
Disabled => IN_DISABLED_STATE,
@@ -196,6 +199,7 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
"visited" => Visited,
"active" => Active,
"focus" => Focus,
+ "fullscreen" => Fullscreen,
"hover" => Hover,
"enabled" => Enabled,
"disabled" => Disabled,
diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs
index 6b124d55d20..4d9683241a8 100644
--- a/components/style/gecko/wrapper.rs
+++ b/components/style/gecko/wrapper.rs
@@ -481,6 +481,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::Disabled |
NonTSPseudoClass::Checked |
NonTSPseudoClass::ReadWrite |
+ NonTSPseudoClass::Fullscreen |
NonTSPseudoClass::Indeterminate => {
self.get_state().contains(pseudo_class.state_flag())
},
diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs
index 8dc844456bd..34eb8c2df7c 100644
--- a/components/style/servo/selector_parser.rs
+++ b/components/style/servo/selector_parser.rs
@@ -90,6 +90,7 @@ pub enum NonTSPseudoClass {
Visited,
Active,
Focus,
+ Fullscreen,
Hover,
Enabled,
Disabled,
@@ -111,6 +112,7 @@ impl ToCss for NonTSPseudoClass {
Visited => ":visited",
Active => ":active",
Focus => ":focus",
+ Fullscreen => ":fullscreen",
Hover => ":hover",
Enabled => ":enabled",
Disabled => ":disabled",
@@ -132,6 +134,7 @@ impl NonTSPseudoClass {
match *self {
Active => IN_ACTIVE_STATE,
Focus => IN_FOCUS_STATE,
+ Fullscreen => IN_FULLSCREEN_STATE,
Hover => IN_HOVER_STATE,
Enabled => IN_ENABLED_STATE,
Disabled => IN_DISABLED_STATE,
@@ -187,6 +190,7 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
"visited" => Visited,
"active" => Active,
"focus" => Focus,
+ "fullscreen" => Fullscreen,
"hover" => Hover,
"enabled" => Enabled,
"disabled" => Disabled,
diff --git a/ports/cef/window.rs b/ports/cef/window.rs
index 16ea145bf0c..33a1c5749c6 100644
--- a/ports/cef/window.rs
+++ b/ports/cef/window.rs
@@ -238,6 +238,9 @@ impl WindowMethods for Window {
}
+ fn set_fullscreen_state(&self, _state: bool) {
+ }
+
fn present(&self) {
let browser = self.cef_browser.borrow();
match *browser {
diff --git a/ports/glutin/window.rs b/ports/glutin/window.rs
index 11953f64b92..c19836cb4f4 100644
--- a/ports/glutin/window.rs
+++ b/ports/glutin/window.rs
@@ -841,6 +841,15 @@ impl WindowMethods for Window {
}
}
+ fn set_fullscreen_state(&self, _state: bool) {
+ match self.kind {
+ WindowKind::Window(..) => {
+ warn!("Fullscreen is not implemented!")
+ },
+ WindowKind::Headless(..) => {}
+ }
+ }
+
fn present(&self) {
match self.kind {
WindowKind::Window(ref window) => {
diff --git a/resources/user-agent.css b/resources/user-agent.css
index 9d2c2508d98..141b9b21de9 100644
--- a/resources/user-agent.css
+++ b/resources/user-agent.css
@@ -286,3 +286,25 @@ video { object-fit: contain; }
textarea { white-space: pre-wrap; }
+
+*|*:not(:root):fullscreen {
+ position:fixed !important;
+ top:0 !important; right:0 !important; bottom:0 !important; left:0 !important;
+ margin:0 !important;
+ box-sizing:border-box !important;
+ min-width:0 !important;
+ max-width:none !important;
+ min-height:0 !important;
+ max-height:none !important;
+ width:100% !important;
+ height:100% !important;
+ transform:none !important;
+
+ /* intentionally not !important */
+ object-fit:contain;
+}
+
+iframe:fullscreen {
+ border:none !important;
+ padding:0 !important;
+}
diff --git a/tests/wpt/include.ini b/tests/wpt/include.ini
index c784afdaad7..63631c662cb 100644
--- a/tests/wpt/include.ini
+++ b/tests/wpt/include.ini
@@ -21,6 +21,8 @@ skip: true
skip: false
[FileAPI]
skip: false
+[fullscreen]
+ skip: false
[hr-time]
skip: false
[html]
diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini
index b602f533384..4961fca1f35 100644
--- a/tests/wpt/metadata/html/dom/interfaces.html.ini
+++ b/tests/wpt/metadata/html/dom/interfaces.html.ini
@@ -1305,9 +1305,6 @@
[HTMLIFrameElement interface: attribute seamless]
expected: FAIL
- [HTMLIFrameElement interface: attribute allowFullscreen]
- expected: FAIL
-
[HTMLIFrameElement interface: attribute align]
expected: FAIL
diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html.ini
index b7750351f19..021d2d2fa06 100644
--- a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html.ini
+++ b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html.ini
@@ -1,8 +1,5 @@
[iframe-allowfullscreen.html]
type: testharness
- [iframe-allowfullscreen]
- expected: FAIL
-
[iframe-sandbox-allowfullscreen]
expected: FAIL
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index bc3a420f79c..23b77f9ed85 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -8132,6 +8132,12 @@
"url": "/_mozilla/mozilla/form_tab_keyevent.html"
}
],
+ "mozilla/fullscreen-remove-single.html": [
+ {
+ "path": "mozilla/fullscreen-remove-single.html",
+ "url": "/_mozilla/mozilla/fullscreen-remove-single.html"
+ }
+ ],
"mozilla/getBoundingClientRect.html": [
{
"path": "mozilla/getBoundingClientRect.html",
diff --git a/tests/wpt/mozilla/tests/mozilla/fullscreen-remove-single.html b/tests/wpt/mozilla/tests/mozilla/fullscreen-remove-single.html
new file mode 100644
index 00000000000..1e3246f791d
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/fullscreen-remove-single.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>Remove the single element on the fullscreen element stack</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<div id="single"></div>
+<script>
+ async_test(function(t)
+ {
+ var single = document.getElementById("single");
+ document.onfullscreenchange = t.step_func(function()
+ {
+ assert_equals(document.fullscreenElement, single);
+ document.onfullscreenchange = t.step_func(function()
+ {
+ assert_equals(document.fullscreenElement, null);
+ t.done();
+ });
+ single.remove();
+ });
+ single.requestFullscreen();
+ });
+</script>
diff --git a/tests/wpt/web-platform-tests/fullscreen/api/blank.html b/tests/wpt/web-platform-tests/fullscreen/api/blank.html
new file mode 100644
index 00000000000..e149a394349
--- /dev/null
+++ b/tests/wpt/web-platform-tests/fullscreen/api/blank.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Title</title>
+</head>
+<body>
+
+</body>
+</html>
diff --git a/tests/wpt/web-platform-tests/fullscreen/api/document-fullscreen-enabled.html b/tests/wpt/web-platform-tests/fullscreen/api/document-fullscreen-enabled.html
index d45bb1576e9..f6382e64083 100644
--- a/tests/wpt/web-platform-tests/fullscreen/api/document-fullscreen-enabled.html
+++ b/tests/wpt/web-platform-tests/fullscreen/api/document-fullscreen-enabled.html
@@ -3,15 +3,23 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
-<iframe></iframe>
-<iframe allowfullscreen></iframe>
+<iframe src="blank.html"></iframe>
+<iframe allowfullscreen src="blank.html"></iframe>
<script>
-test(function()
+async_test(function(t)
{
assert_true(document.fullscreenEnabled, "top-level document");
var iframes = document.getElementsByTagName("iframe");
- assert_false(iframes[0].contentDocument.fullscreenEnabled, "iframe without allowfullscreen");
- assert_true(iframes[1].contentDocument.fullscreenEnabled, "iframe with allowfullscreen");
+
+ var loaded = 0;
+ iframes[0].onload = t.step_func(function() {
+ assert_false(iframes[0].contentDocument.fullscreenEnabled, "iframe without allowfullscreen");
+ if (++loaded == 2) t.done();
+ });
+ iframes[1].onload = t.step_func(function() {
+ assert_true(iframes[1].contentDocument.fullscreenEnabled, "iframe with allowfullscreen");
+ if (++loaded == 2) t.done();
+ });
});
</script>
diff --git a/tests/wpt/web-platform-tests/fullscreen/api/document-onfullscreenerror.html b/tests/wpt/web-platform-tests/fullscreen/api/document-onfullscreenerror.html
index f5eaaf44146..9bbcda9bba1 100644
--- a/tests/wpt/web-platform-tests/fullscreen/api/document-onfullscreenerror.html
+++ b/tests/wpt/web-platform-tests/fullscreen/api/document-onfullscreenerror.html
@@ -6,8 +6,13 @@
<script>
async_test(function(t)
{
+ var sync = true;
assert_equals(document.onfullscreenerror, null, "initial onfullscreenerror");
- document.onfullscreenerror = t.step_func_done();
- document.createElement("a").requestFullscreen();
+ document.onfullscreenerror = t.step_func_done(function(event) {
+ assert_false(sync);
+ });
+ var e = document.createElement('span');
+ e.requestFullscreen();
+ sync = false;
});
</script>