aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
authorGlenn Watson <gw@intuitionlibrary.com>2015-07-27 15:20:27 +1000
committerGlenn Watson <gw@intuitionlibrary.com>2015-08-03 11:55:38 +1000
commit9e5687e3e72f2c79bf17bcfb33ea33f0659377ac (patch)
tree747b19a3de028cebc1dca77f6edd1a38fba1cf33 /components/script/dom
parent1809748dc12ec63e3179b66109c91983f744c235 (diff)
downloadservo-9e5687e3e72f2c79bf17bcfb33ea33f0659377ac.tar.gz
servo-9e5687e3e72f2c79bf17bcfb33ea33f0659377ac.zip
Implement offsetParent/Top/Left/Width/Height.
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/htmlelement.rs59
-rw-r--r--components/script/dom/webidls/HTMLElement.webidl11
-rw-r--r--components/script/dom/window.rs27
3 files changed, 94 insertions, 3 deletions
diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs
index 513a9d39775..376bec890cc 100644
--- a/components/script/dom/htmlelement.rs
+++ b/components/script/dom/htmlelement.rs
@@ -12,7 +12,7 @@ use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementM
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDerived};
use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLInputElementCast, NodeCast};
-use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived};
+use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived, HTMLHtmlElementDerived};
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::error::ErrorResult;
use dom::bindings::error::Error::Syntax;
@@ -216,6 +216,63 @@ impl<'a> HTMLElementMethods for &'a HTMLElement {
// If `request_focus` is not called, focus will be set to None.
document.r().commit_focus_transaction(FocusType::Element);
}
+
+ // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
+ fn GetOffsetParent(self) -> Option<Root<Element>> {
+ if self.is_htmlbodyelement() || self.is_htmlhtmlelement() {
+ return None;
+ }
+
+ let node = NodeCast::from_ref(self);
+ let window = window_from_node(self);
+ let (element, _) = window.offset_parent_query(node.to_trusted_node_address());
+
+ element
+ }
+
+ // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
+ fn OffsetTop(self) -> i32 {
+ if self.is_htmlbodyelement() {
+ return 0;
+ }
+
+ let node = NodeCast::from_ref(self);
+ let window = window_from_node(self);
+ let (_, rect) = window.offset_parent_query(node.to_trusted_node_address());
+
+ rect.origin.y.to_nearest_px()
+ }
+
+ // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
+ fn OffsetLeft(self) -> i32 {
+ if self.is_htmlbodyelement() {
+ return 0;
+ }
+
+ let node = NodeCast::from_ref(self);
+ let window = window_from_node(self);
+ let (_, rect) = window.offset_parent_query(node.to_trusted_node_address());
+
+ rect.origin.x.to_nearest_px()
+ }
+
+ // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
+ fn OffsetWidth(self) -> i32 {
+ let node = NodeCast::from_ref(self);
+ let window = window_from_node(self);
+ let (_, rect) = window.offset_parent_query(node.to_trusted_node_address());
+
+ rect.size.width.to_nearest_px()
+ }
+
+ // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
+ fn OffsetHeight(self) -> i32 {
+ let node = NodeCast::from_ref(self);
+ let window = window_from_node(self);
+ let (_, rect) = window.offset_parent_query(node.to_trusted_node_address());
+
+ rect.size.height.to_nearest_px()
+ }
}
// https://html.spec.whatwg.org/#attr-data-*
diff --git a/components/script/dom/webidls/HTMLElement.webidl b/components/script/dom/webidls/HTMLElement.webidl
index f4c0376b618..90b11d85bff 100644
--- a/components/script/dom/webidls/HTMLElement.webidl
+++ b/components/script/dom/webidls/HTMLElement.webidl
@@ -45,5 +45,16 @@ interface HTMLElement : Element {
//readonly attribute boolean? commandDisabled;
//readonly attribute boolean? commandChecked;
};
+
+// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-htmlelement-interface
+partial interface HTMLElement {
+ // CSSOM things are not [Pure] because they can flush
+ readonly attribute Element? offsetParent;
+ readonly attribute long offsetTop;
+ readonly attribute long offsetLeft;
+ readonly attribute long offsetWidth;
+ readonly attribute long offsetHeight;
+};
+
HTMLElement implements GlobalEventHandlers;
HTMLElement implements ElementCSSInlineStyle;
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index d7a9e9f243a..1320ca354b9 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::EventHandlerBinding::{OnErrorEventHandlerN
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::codegen::Bindings::WindowBinding::{self, WindowMethods, FrameRequestCallback};
-use dom::bindings::codegen::InheritTypes::{NodeCast, EventTargetCast};
+use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, EventTargetCast};
use dom::bindings::global::global_object_for_js_object;
use dom::bindings::error::{report_pending_exception, Fallible};
use dom::bindings::error::Error::InvalidCharacter;
@@ -27,7 +27,7 @@ use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::location::Location;
use dom::navigator::Navigator;
-use dom::node::{window_from_node, TrustedNodeAddress, NodeHelpers};
+use dom::node::{window_from_node, TrustedNodeAddress, NodeHelpers, from_untrusted_node_address};
use dom::performance::Performance;
use dom::screen::Screen;
use dom::storage::Storage;
@@ -578,6 +578,7 @@ pub trait WindowHelpers {
fn client_rect_query(self, node_geometry_request: TrustedNodeAddress) -> Rect<i32>;
fn resolved_style_query(self, element: TrustedNodeAddress,
pseudo: Option<PseudoElement>, property: &Atom) -> Option<String>;
+ fn offset_parent_query(self, node: TrustedNodeAddress) -> (Option<Root<Element>>, Rect<Au>);
fn handle_reflow_complete_msg(self, reflow_id: u32);
fn set_fragment_name(self, fragment: Option<String>);
fn steal_fragment_name(self) -> Option<String>;
@@ -827,6 +828,27 @@ impl<'a> WindowHelpers for &'a Window {
resolved
}
+ fn offset_parent_query(self, node: TrustedNodeAddress) -> (Option<Root<Element>>, Rect<Au>) {
+ self.reflow(ReflowGoal::ForScriptQuery,
+ ReflowQueryType::OffsetParentQuery(node),
+ ReflowReason::Query);
+ let response = self.layout_rpc.offset_parent();
+ let js_runtime = self.js_runtime.borrow();
+ let js_runtime = js_runtime.as_ref().unwrap();
+ let element = match response.node_address {
+ Some(parent_node_address) => {
+ let node = from_untrusted_node_address(js_runtime.rt(),
+ parent_node_address);
+ let element = ElementCast::to_ref(node.r()).unwrap();
+ Some(Root::from_ref(element))
+ }
+ None => {
+ None
+ }
+ };
+ (element, response.rect)
+ }
+
fn handle_reflow_complete_msg(self, reflow_id: u32) {
let last_reflow_id = self.last_reflow_id.get();
if last_reflow_id == reflow_id {
@@ -1135,6 +1157,7 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason:
ReflowQueryType::ContentBoxesQuery(_n) => "\tContentBoxesQuery",
ReflowQueryType::NodeGeometryQuery(_n) => "\tNodeGeometryQuery",
ReflowQueryType::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery",
+ ReflowQueryType::OffsetParentQuery(_n) => "\tOffsetParentQuery",
});
debug_msg.push_str(match *reason {