aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/element.rs
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 /components/script/dom/element.rs
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 -->
Diffstat (limited to 'components/script/dom/element.rs')
-rw-r--r--components/script/dom/element.rs149
1 files changed, 148 insertions, 1 deletions
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());
+ }
+}