mirror of
https://github.com/servo/servo.git
synced 2025-06-13 02:44:29 +00:00
Implement ScrollTop and ScrollLeft getters:
Add new compositor message to get scroll_offset; Add new layout query for computed value of overflow-x/y; Implement layer_id method for ThreadSafeLayoutNode; Add new layout query for layer_id; Implement script interface for getting scrollTop and scrollLeft, as well as relavant helper functions.
This commit is contained in:
parent
f73c6143d5
commit
fefdaf76de
12 changed files with 243 additions and 9 deletions
|
@ -19,6 +19,7 @@ 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::UnionTypes::NodeOrString;
|
||||
use dom::bindings::error::{Error, ErrorResult, Fallible};
|
||||
use dom::bindings::global::GlobalRef;
|
||||
|
@ -39,6 +40,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 +88,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 +166,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)]
|
||||
|
@ -1452,6 +1483,68 @@ impl ElementMethods for Element {
|
|||
rect.size.height.to_f64_px())
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-element-scrolltop
|
||||
fn ScrollTop(&self) -> f64 {
|
||||
let node = self.upcast::<Node>();
|
||||
|
||||
// 1. Let document be the element’s node document.
|
||||
let doc = node.owner_doc();
|
||||
|
||||
// 2. If the document is not the active document, return zero and terminate these steps.
|
||||
if !doc.is_fully_active() {
|
||||
return 0.0;
|
||||
} else {
|
||||
// 3. Let window be the value of document’s defaultView attribute.
|
||||
let win = doc.DefaultView();
|
||||
|
||||
// 5. If the element is the root element and document is in quirks mode,
|
||||
// return zero and terminate these steps.
|
||||
if *self.root_element() == *self {
|
||||
if doc.quirks_mode() == Quirks {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// 6. If the element is the root element return the value of scrollY on window.
|
||||
return (*win).ScrollY() as f64;
|
||||
}
|
||||
|
||||
// 7. If the element is the HTML body element, document is in quirks mode,
|
||||
// and the element is not potentially scrollable, return the value of scrollY on window.
|
||||
if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
|
||||
doc.quirks_mode() == Quirks &&
|
||||
!self.potentially_scrollable() {
|
||||
return (*win).ScrollY() as f64;
|
||||
}
|
||||
|
||||
|
||||
// 8. If the element does not have any associated CSS layout box, return zero and terminate these steps.
|
||||
if !self.has_css_layout_box() {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// 9. Return the y-coordinate of the scrolling area at the alignment point
|
||||
// with the top of the padding edge of the element.
|
||||
let point = node.scroll_offset();
|
||||
return -point.y as f64;
|
||||
}
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-element-scrolltop
|
||||
fn SetScrollTop(&self, _scroll_top: f64) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-element-scrollleft
|
||||
fn ScrollLeft(&self) -> f64 {
|
||||
let point = self.upcast::<Node>().scroll_offset();
|
||||
return -point.x as f64;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-element-scrollleft
|
||||
fn SetScrollLeft(&self, _scroll_left: f64) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-element-scrollwidth
|
||||
fn ScrollWidth(&self) -> i32 {
|
||||
self.upcast::<Node>().scroll_area().size.width
|
||||
|
|
|
@ -614,6 +614,12 @@ impl Node {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn scroll_offset(&self) -> Point2D<f32> {
|
||||
let document = self.owner_doc();
|
||||
let window = document.window();
|
||||
window.scroll_offset_query(self.to_trusted_node_address())
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-childnode-before
|
||||
pub fn before(&self, nodes: Vec<NodeOrString>) -> ErrorResult {
|
||||
// Step 1.
|
||||
|
|
|
@ -81,6 +81,8 @@ partial interface Element {
|
|||
DOMRectList getClientRects();
|
||||
DOMRect getBoundingClientRect();
|
||||
|
||||
attribute unrestricted double scrollTop;
|
||||
attribute unrestricted double scrollLeft;
|
||||
readonly attribute long scrollWidth;
|
||||
readonly attribute long scrollHeight;
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ use std::sync::{Arc, Mutex};
|
|||
use string_cache::Atom;
|
||||
use style::context::ReflowGoal;
|
||||
use style::error_reporting::ParseErrorReporter;
|
||||
use style::properties::longhands::{overflow_x};
|
||||
use style::selector_impl::PseudoElement;
|
||||
use task_source::TaskSource;
|
||||
use task_source::dom_manipulation::{DOMManipulationTaskSource, DOMManipulationTask};
|
||||
|
@ -1122,6 +1123,25 @@ impl Window {
|
|||
self.layout_rpc.node_scroll_area().client_rect
|
||||
}
|
||||
|
||||
pub fn overflow_query(&self, node: TrustedNodeAddress) -> Point2D<overflow_x::computed_value::T> {
|
||||
self.reflow(ReflowGoal::ForScriptQuery,
|
||||
ReflowQueryType::NodeOverflowQuery(node),
|
||||
ReflowReason::Query);
|
||||
self.layout_rpc.node_overflow().0.unwrap()
|
||||
}
|
||||
|
||||
pub fn scroll_offset_query(&self, node: TrustedNodeAddress) -> Point2D<f32> {
|
||||
self.reflow(ReflowGoal::ForScriptQuery,
|
||||
ReflowQueryType::NodeLayerIdQuery(node),
|
||||
ReflowReason::Query);
|
||||
let layer_id = self.layout_rpc.node_layer_id().layer_id;
|
||||
let pipeline_id = self.id;
|
||||
|
||||
let (send, recv) = ipc::channel::<Point2D<f32>>().unwrap();
|
||||
self.compositor.send(ScriptToCompositorMsg::GetScrollOffset(pipeline_id, layer_id, send)).unwrap();
|
||||
recv.recv().unwrap_or(Point2D::zero())
|
||||
}
|
||||
|
||||
pub fn resolved_style_query(&self,
|
||||
element: TrustedNodeAddress,
|
||||
pseudo: Option<PseudoElement>,
|
||||
|
@ -1476,6 +1496,8 @@ fn debug_reflow_events(id: PipelineId, goal: &ReflowGoal, query_type: &ReflowQue
|
|||
ReflowQueryType::ContentBoxesQuery(_n) => "\tContentBoxesQuery",
|
||||
ReflowQueryType::HitTestQuery(_n, _o) => "\tHitTestQuery",
|
||||
ReflowQueryType::NodeGeometryQuery(_n) => "\tNodeGeometryQuery",
|
||||
ReflowQueryType::NodeLayerIdQuery(_n) => "\tNodeLayerIdQuery",
|
||||
ReflowQueryType::NodeOverflowQuery(_n) => "\tNodeOverFlowQuery",
|
||||
ReflowQueryType::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery",
|
||||
ReflowQueryType::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery",
|
||||
ReflowQueryType::OffsetParentQuery(_n) => "\tOffsetParentQuery",
|
||||
|
|
|
@ -23,7 +23,7 @@ use std::sync::Arc;
|
|||
use std::sync::mpsc::{Receiver, Sender, channel};
|
||||
use string_cache::Atom;
|
||||
use style::context::ReflowGoal;
|
||||
use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left};
|
||||
use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left, overflow_x};
|
||||
use style::selector_impl::PseudoElement;
|
||||
use style::servo::Stylesheet;
|
||||
use url::Url;
|
||||
|
@ -104,8 +104,12 @@ pub trait LayoutRPC {
|
|||
fn content_boxes(&self) -> ContentBoxesResponse;
|
||||
/// Requests the geometry of this node. Used by APIs such as `clientTop`.
|
||||
fn node_geometry(&self) -> NodeGeometryResponse;
|
||||
/// Requests the overflow-x and overflow-y of this node. Used by `scrollTop` etc.
|
||||
fn node_overflow(&self) -> NodeOverflowResponse;
|
||||
/// Requests the scroll geometry of this node. Used by APIs such as `scrollTop`.
|
||||
fn node_scroll_area(&self) -> NodeGeometryResponse;
|
||||
/// Requests the layer id of this node. Used by APIs such as `scrollTop`
|
||||
fn node_layer_id(&self) -> NodeLayerIdResponse;
|
||||
/// Requests the node containing the point of interest
|
||||
fn hit_test(&self) -> HitTestResponse;
|
||||
/// Query layout for the resolved value of a given CSS property
|
||||
|
@ -136,6 +140,8 @@ impl MarginStyleResponse {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct NodeOverflowResponse(pub Option<Point2D<overflow_x::computed_value::T>>);
|
||||
|
||||
pub struct ContentBoxResponse(pub Rect<Au>);
|
||||
pub struct ContentBoxesResponse(pub Vec<Rect<Au>>);
|
||||
pub struct HitTestResponse {
|
||||
|
@ -144,6 +150,11 @@ pub struct HitTestResponse {
|
|||
pub struct NodeGeometryResponse {
|
||||
pub client_rect: Rect<i32>,
|
||||
}
|
||||
|
||||
pub struct NodeLayerIdResponse {
|
||||
pub layer_id: LayerId,
|
||||
}
|
||||
|
||||
pub struct ResolvedStyleResponse(pub Option<String>);
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -167,8 +178,10 @@ pub enum ReflowQueryType {
|
|||
NoQuery,
|
||||
ContentBoxQuery(TrustedNodeAddress),
|
||||
ContentBoxesQuery(TrustedNodeAddress),
|
||||
NodeOverflowQuery(TrustedNodeAddress),
|
||||
HitTestQuery(Point2D<f32>, bool),
|
||||
NodeGeometryQuery(TrustedNodeAddress),
|
||||
NodeLayerIdQuery(TrustedNodeAddress),
|
||||
NodeScrollGeometryQuery(TrustedNodeAddress),
|
||||
ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, Atom),
|
||||
OffsetParentQuery(TrustedNodeAddress),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue