diff options
Diffstat (limited to 'components/script/dom/element.rs')
-rw-r--r-- | components/script/dom/element.rs | 298 |
1 files changed, 296 insertions, 2 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index e14e1af0d97..d5151dc7dfd 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -19,6 +19,8 @@ use dom::bindings::codegen::Bindings::EventBinding::EventMethods; use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; use dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; +use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions}; use dom::bindings::codegen::UnionTypes::NodeOrString; use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::global::GlobalRef; @@ -39,6 +41,7 @@ use dom::htmlanchorelement::HTMLAnchorElement; use dom::htmlbodyelement::{HTMLBodyElement, HTMLBodyElementLayoutHelpers}; use dom::htmlbuttonelement::HTMLButtonElement; use dom::htmlcollection::HTMLCollection; +use dom::htmlelement::HTMLElement; use dom::htmlfieldsetelement::HTMLFieldSetElement; use dom::htmlfontelement::{HTMLFontElement, HTMLFontElementLayoutHelpers}; use dom::htmlhrelement::{HTMLHRElement, HTMLHRLayoutHelpers}; @@ -86,7 +89,7 @@ use string_cache::{Atom, Namespace, QualName}; use style::element_state::*; use style::error_reporting::ParseErrorReporter; use style::properties::DeclaredValue; -use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size}; +use style::properties::longhands::{self, background_image, border_spacing, font_family, overflow_x, font_size}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute}; use style::selector_impl::{NonTSPseudoClass, ServoSelectorImpl}; use style::values::CSSFloat; @@ -164,6 +167,35 @@ impl Element { document, ElementBinding::Wrap) } + + // https://drafts.csswg.org/cssom-view/#css-layout-box + // Elements that have a computed value of the display property + // that is table-column or table-column-group + // FIXME: Currently, it is assumed to be true always + fn has_css_layout_box(&self) -> bool { + true + } + + // https://drafts.csswg.org/cssom-view/#potentially-scrollable + fn potentially_scrollable(&self) -> bool { + self.has_css_layout_box() && + !self.overflow_x_is_visible() && + !self.overflow_y_is_visible() + } + + // used value of overflow-x is "visible" + fn overflow_x_is_visible(&self) -> bool { + let window = window_from_node(self); + let overflow_pair = window.overflow_query(self.upcast::<Node>().to_trusted_node_address()); + overflow_pair.x == overflow_x::computed_value::T::visible + } + + // used value of overflow-y is "visible" + fn overflow_y_is_visible(&self) -> bool { + let window = window_from_node(self); + let overflow_pair = window.overflow_query(self.upcast::<Node>().to_trusted_node_address()); + overflow_pair.y != overflow_x::computed_value::T::visible + } } #[allow(unsafe_code)] @@ -1081,7 +1113,7 @@ impl Element { // https://html.spec.whatwg.org/multipage/#reflect // XXXManishearth this doesn't handle `javascript:` urls properly match base.join(&url) { - Ok(parsed) => DOMString::from(parsed.serialize()), + Ok(parsed) => DOMString::from(parsed.into_string()), Err(_) => DOMString::from(""), } } @@ -1196,6 +1228,49 @@ impl Element { _ => Err(Error::Syntax) } } + + // https://drafts.csswg.org/cssom-view/#dom-element-scroll + pub fn scroll(&self, x_: f64, y_: f64, behavior: ScrollBehavior) { + + // Step 1.2 or 2.3 + let x = if x_.is_finite() { x_ } else { 0.0f64 }; + let y = if y_.is_finite() { y_ } else { 0.0f64 }; + + let node = self.upcast::<Node>(); + + // Step 3 + let doc = node.owner_doc(); + + // Step 4 + if !doc.is_fully_active() { + return; + } + + // Step 5 + let win = doc.DefaultView(); + + // Step 7 + if *self.root_element() == *self { + if doc.quirks_mode() != Quirks { + win.scroll(x, y, behavior); + } + + return; + } + + // Step 9 + if doc.GetBody().r() == self.downcast::<HTMLElement>() && + doc.quirks_mode() == Quirks && + !self.potentially_scrollable() { + win.scroll(x, y, behavior); + return; + } + + // Step 10 (TODO) + + // Step 11 + win.scroll_node(node.to_trusted_node_address(), x, y, behavior); + } } impl ElementMethods for Element { @@ -1260,6 +1335,11 @@ impl ElementMethods for Element { self.attr_list.or_init(|| NamedNodeMap::new(&window_from_node(self), self)) } + // https://dom.spec.whatwg.org/#dom-element-hasattributes + fn HasAttributes(&self) -> bool { + !self.attrs.borrow().is_empty() + } + // https://dom.spec.whatwg.org/#dom-element-getattributenames fn GetAttributeNames(&self) -> Vec<DOMString> { self.attrs.borrow().iter().map(|attr| attr.Name()).collect() @@ -1452,6 +1532,220 @@ impl ElementMethods for Element { rect.size.height.to_f64_px()) } + // https://drafts.csswg.org/cssom-view/#dom-element-scroll + fn Scroll(&self, options: &ScrollToOptions) { + // Step 1 + let left = options.left.unwrap_or(self.ScrollLeft()); + let top = options.top.unwrap_or(self.ScrollTop()); + self.scroll(left, top, options.parent.behavior); + } + + // https://drafts.csswg.org/cssom-view/#dom-element-scroll + fn Scroll_(&self, x: f64, y: f64) { + self.scroll(x, y, ScrollBehavior::Auto); + } + + // https://drafts.csswg.org/cssom-view/#dom-element-scrollto + fn ScrollTo(&self, options: &ScrollToOptions) { + self.Scroll(options); + } + + // https://drafts.csswg.org/cssom-view/#dom-element-scrollto + fn ScrollTo_(&self, x: f64, y: f64) { + self.Scroll_(x, y); + } + + // https://drafts.csswg.org/cssom-view/#dom-element-scrollby + fn ScrollBy(&self, options: &ScrollToOptions) { + // Step 2 + let delta_left = options.left.unwrap_or(0.0f64); + let delta_top = options.top.unwrap_or(0.0f64); + let left = self.ScrollLeft(); + let top = self.ScrollTop(); + self.scroll(left + delta_left, top + delta_top, + options.parent.behavior); + } + + // https://drafts.csswg.org/cssom-view/#dom-element-scrollby + fn ScrollBy_(&self, x: f64, y: f64) { + let left = self.ScrollLeft(); + let top = self.ScrollTop(); + self.scroll(left + x, top + y, ScrollBehavior::Auto); + } + + // https://drafts.csswg.org/cssom-view/#dom-element-scrolltop + fn ScrollTop(&self) -> f64 { + let node = self.upcast::<Node>(); + + // Step 1 + let doc = node.owner_doc(); + + // Step 2 + if !doc.is_fully_active() { + return 0.0; + } + + // Step 3 + let win = doc.DefaultView(); + + // Step 5 + if *self.root_element() == *self { + if doc.quirks_mode() == Quirks { + return 0.0; + } + + // Step 6 + return win.ScrollY() as f64; + } + + // Step 7 + if doc.GetBody().r() == self.downcast::<HTMLElement>() && + doc.quirks_mode() == Quirks && + !self.potentially_scrollable() { + return win.ScrollY() as f64; + } + + + // Step 8 + if !self.has_css_layout_box() { + return 0.0; + } + + // Step 9 + let point = node.scroll_offset(); + return point.y.abs() as f64; + } + + // https://drafts.csswg.org/cssom-view/#dom-element-scrolltop + fn SetScrollTop(&self, y_: f64) { + let behavior = ScrollBehavior::Auto; + + // Step 1, 2 + let y = if y_.is_finite() { y_ } else { 0.0f64 }; + + let node = self.upcast::<Node>(); + + // Step 3 + let doc = node.owner_doc(); + + // Step 4 + if !doc.is_fully_active() { + return; + } + + // Step 5 + let win = doc.DefaultView(); + + // Step 7 + if *self.root_element() == *self { + if doc.quirks_mode() != Quirks { + win.scroll(win.ScrollX() as f64, y, behavior); + } + + return; + } + + // Step 9 + if doc.GetBody().r() == self.downcast::<HTMLElement>() && + doc.quirks_mode() == Quirks && + !self.potentially_scrollable() { + win.scroll(win.ScrollX() as f64, y, behavior); + return; + } + + // Step 10 (TODO) + + // Step 11 + win.scroll_node(node.to_trusted_node_address(), self.ScrollLeft(), y, behavior); + } + + // https://drafts.csswg.org/cssom-view/#dom-element-scrolltop + fn ScrollLeft(&self) -> f64 { + let node = self.upcast::<Node>(); + + // Step 1 + let doc = node.owner_doc(); + + // Step 2 + if !doc.is_fully_active() { + return 0.0; + } + + // Step 3 + let win = doc.DefaultView(); + + // Step 5 + if *self.root_element() == *self { + if doc.quirks_mode() != Quirks { + // Step 6 + return win.ScrollX() as f64; + } + + return 0.0; + } + + // Step 7 + if doc.GetBody().r() == self.downcast::<HTMLElement>() && + doc.quirks_mode() == Quirks && + !self.potentially_scrollable() { + return win.ScrollX() as f64; + } + + + // Step 8 + if !self.has_css_layout_box() { + return 0.0; + } + + // Step 9 + let point = node.scroll_offset(); + return point.x.abs() as f64; + } + + // https://drafts.csswg.org/cssom-view/#dom-element-scrollleft + fn SetScrollLeft(&self, x_: f64) { + let behavior = ScrollBehavior::Auto; + + // Step 1, 2 + let x = if x_.is_finite() { x_ } else { 0.0f64 }; + + let node = self.upcast::<Node>(); + + // Step 3 + let doc = node.owner_doc(); + + // Step 4 + if !doc.is_fully_active() { + return; + } + + // Step 5 + let win = doc.DefaultView(); + + // Step 7 + if *self.root_element() == *self { + if doc.quirks_mode() == Quirks { + return; + } + + win.scroll(x, win.ScrollY() as f64, behavior); + return; + } + + // Step 9 + if doc.GetBody().r() == self.downcast::<HTMLElement>() && + doc.quirks_mode() == Quirks && + !self.potentially_scrollable() { + win.scroll(x, win.ScrollY() as f64, behavior); + return; + } + + // Step 10 (TODO) + + // Step 11 + win.scroll_node(node.to_trusted_node_address(), x, self.ScrollTop(), behavior); + } + // https://drafts.csswg.org/cssom-view/#dom-element-scrollwidth fn ScrollWidth(&self) -> i32 { self.upcast::<Node>().scroll_area().size.width |