mirror of
https://github.com/servo/servo.git
synced 2025-07-30 02:30:21 +01:00
Auto merge of #9824 - danlrobertson:element1, r=asajeffrey
Add the scrollWidth and scrollHeight extensions to the element interface Add the `scrollWidth` and `scrollHeight` extensions to the element interface. My goal was to create a method that encompassed getting `scrollWidth`, `scrollHeight`, `scrollTop`, and `scrollLeft`. I also noted that `clientHeight` and `clientWidth` to not handle the root element and the body element correctly. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.svg" height="40" alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9824) <!-- Reviewable:end -->
This commit is contained in:
commit
7ff7932a8c
10 changed files with 234 additions and 39 deletions
|
@ -43,7 +43,7 @@ use profile_traits::mem::{self, Report, ReportKind, ReportsChan};
|
|||
use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
|
||||
use profile_traits::time::{self, TimerMetadata, profile};
|
||||
use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_request};
|
||||
use query::{process_node_geometry_request, process_offset_parent_query};
|
||||
use query::{process_node_geometry_request, process_node_scroll_area_request, process_offset_parent_query};
|
||||
use query::{process_resolved_style_request, process_margin_style_query};
|
||||
use script::dom::node::OpaqueStyleAndLayoutData;
|
||||
use script::layout_interface::{LayoutRPC, OffsetParentResponse, MarginStyleResponse};
|
||||
|
@ -117,6 +117,9 @@ pub struct LayoutThreadData {
|
|||
/// A queued response for the node at a given point
|
||||
pub hit_test_response: (Option<DisplayItemMetadata>, bool),
|
||||
|
||||
/// A queued response for the scroll {top, left, width, height} of a node in pixels.
|
||||
pub scroll_area_response: Rect<i32>,
|
||||
|
||||
/// A queued response for the resolved style property of an element.
|
||||
pub resolved_style_response: Option<String>,
|
||||
|
||||
|
@ -462,6 +465,7 @@ impl LayoutThread {
|
|||
content_boxes_response: Vec::new(),
|
||||
client_rect_response: Rect::zero(),
|
||||
hit_test_response: (None, false),
|
||||
scroll_area_response: Rect::zero(),
|
||||
resolved_style_response: None,
|
||||
offset_parent_response: OffsetParentResponse::empty(),
|
||||
margin_style_response: MarginStyleResponse::empty(),
|
||||
|
@ -989,6 +993,9 @@ impl LayoutThread {
|
|||
ReflowQueryType::NodeGeometryQuery(_) => {
|
||||
rw_data.client_rect_response = Rect::zero();
|
||||
},
|
||||
ReflowQueryType::NodeScrollGeometryQuery(_) => {
|
||||
rw_data.scroll_area_response = Rect::zero();
|
||||
},
|
||||
ReflowQueryType::ResolvedStyleQuery(_, _, _) => {
|
||||
rw_data.resolved_style_response = None;
|
||||
},
|
||||
|
@ -1144,6 +1151,10 @@ impl LayoutThread {
|
|||
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||
rw_data.client_rect_response = process_node_geometry_request(node, &mut root_flow);
|
||||
},
|
||||
ReflowQueryType::NodeScrollGeometryQuery(node) => {
|
||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||
rw_data.scroll_area_response = process_node_scroll_area_request(node, &mut root_flow);
|
||||
},
|
||||
ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => {
|
||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||
rw_data.resolved_style_response =
|
||||
|
|
|
@ -8,6 +8,7 @@ use app_units::Au;
|
|||
use construct::ConstructionResult;
|
||||
use euclid::point::Point2D;
|
||||
use euclid::rect::Rect;
|
||||
use euclid::size::Size2D;
|
||||
use flow;
|
||||
use flow_ref::FlowRef;
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||
|
@ -20,11 +21,12 @@ use script::layout_interface::{HitTestResponse, LayoutRPC, OffsetParentResponse}
|
|||
use script::layout_interface::{ResolvedStyleResponse, ScriptLayoutChan, MarginStyleResponse};
|
||||
use script_traits::LayoutMsg as ConstellationMsg;
|
||||
use sequential;
|
||||
use std::cmp::{min, max};
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use string_cache::Atom;
|
||||
use style::computed_values;
|
||||
use style::logical_geometry::WritingMode;
|
||||
use style::logical_geometry::{WritingMode, BlockFlowDirection, InlineBaseDirection};
|
||||
use style::properties::longhands::{display, position};
|
||||
use style::properties::style_structs;
|
||||
use style::selector_impl::PseudoElement;
|
||||
|
@ -34,6 +36,18 @@ use wrapper::{LayoutNode, ThreadSafeLayoutNode};
|
|||
|
||||
pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutThreadData>>);
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#overflow-directions
|
||||
fn overflow_direction(writing_mode: &WritingMode) -> OverflowDirection {
|
||||
match (writing_mode.block_flow_direction(), writing_mode.inline_base_direction()) {
|
||||
(BlockFlowDirection::TopToBottom, InlineBaseDirection::LeftToRight) |
|
||||
(BlockFlowDirection::LeftToRight, InlineBaseDirection::LeftToRight) => OverflowDirection::RightAndDown,
|
||||
(BlockFlowDirection::TopToBottom, InlineBaseDirection::RightToLeft) |
|
||||
(BlockFlowDirection::RightToLeft, InlineBaseDirection::LeftToRight) => OverflowDirection::LeftAndDown,
|
||||
(BlockFlowDirection::RightToLeft, InlineBaseDirection::RightToLeft) => OverflowDirection::LeftAndUp,
|
||||
(BlockFlowDirection::LeftToRight, InlineBaseDirection::RightToLeft) => OverflowDirection::RightAndUp
|
||||
}
|
||||
}
|
||||
|
||||
impl LayoutRPC for LayoutRPCImpl {
|
||||
|
||||
// The neat thing here is that in order to answer the following two queries we only
|
||||
|
@ -78,6 +92,12 @@ impl LayoutRPC for LayoutRPCImpl {
|
|||
}
|
||||
}
|
||||
|
||||
fn node_scroll_area(&self) -> NodeGeometryResponse {
|
||||
NodeGeometryResponse {
|
||||
client_rect: self.0.lock().unwrap().scroll_area_response
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves the resolved value for a CSS style property.
|
||||
fn resolved_style(&self) -> ResolvedStyleResponse {
|
||||
let &LayoutRPCImpl(ref rw_data) = self;
|
||||
|
@ -174,6 +194,14 @@ enum PositionProperty {
|
|||
Height,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum OverflowDirection {
|
||||
RightAndDown,
|
||||
LeftAndDown,
|
||||
LeftAndUp,
|
||||
RightAndUp,
|
||||
}
|
||||
|
||||
struct PositionRetrievingFragmentBorderBoxIterator {
|
||||
node_address: OpaqueNode,
|
||||
result: Option<Au>,
|
||||
|
@ -291,6 +319,28 @@ impl FragmentLocatingFragmentIterator {
|
|||
}
|
||||
}
|
||||
|
||||
struct UnioningFragmentScrollAreaIterator {
|
||||
node_address: OpaqueNode,
|
||||
union_rect: Rect<i32>,
|
||||
origin_rect: Rect<i32>,
|
||||
level: Option<i32>,
|
||||
is_child: bool,
|
||||
overflow_direction: OverflowDirection
|
||||
}
|
||||
|
||||
impl UnioningFragmentScrollAreaIterator {
|
||||
fn new(node_address: OpaqueNode) -> UnioningFragmentScrollAreaIterator {
|
||||
UnioningFragmentScrollAreaIterator {
|
||||
node_address: node_address,
|
||||
union_rect: Rect::zero(),
|
||||
origin_rect: Rect::zero(),
|
||||
level: None,
|
||||
is_child: false,
|
||||
overflow_direction: OverflowDirection::RightAndDown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ParentBorderBoxInfo {
|
||||
node_address: OpaqueNode,
|
||||
border_box: Rect<Au>,
|
||||
|
@ -336,6 +386,53 @@ impl FragmentBorderBoxIterator for FragmentLocatingFragmentIterator {
|
|||
}
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#scrolling-area
|
||||
impl FragmentBorderBoxIterator for UnioningFragmentScrollAreaIterator {
|
||||
fn process(&mut self, fragment: &Fragment, level: i32, border_box: &Rect<Au>) {
|
||||
// In cases in which smaller child elements contain less padding than the parent
|
||||
// the a union of the two elements padding rectangles could result in an unwanted
|
||||
// increase in size. To work around this, we store the original elements padding
|
||||
// rectangle as `origin_rect` and the union of all child elements padding and
|
||||
// margin rectangles as `union_rect`.
|
||||
let style_structs::Border {
|
||||
border_top_width: top_border,
|
||||
border_right_width: right_border,
|
||||
border_bottom_width: bottom_border,
|
||||
border_left_width: left_border,
|
||||
..
|
||||
} = *fragment.style.get_border();
|
||||
let right_padding = (border_box.size.width - right_border - left_border).to_px();
|
||||
let bottom_padding = (border_box.size.height - bottom_border - top_border).to_px();
|
||||
let top_padding = top_border.to_px();
|
||||
let left_padding = left_border.to_px();
|
||||
match self.level {
|
||||
Some(start_level) if level <= start_level => { self.is_child = false; }
|
||||
Some(_) => {
|
||||
let padding = Rect::new(Point2D::new(left_padding, top_padding),
|
||||
Size2D::new(right_padding, bottom_padding));
|
||||
let top_margin = fragment.margin.top(fragment.style.writing_mode).to_px();
|
||||
let left_margin = fragment.margin.left(fragment.style.writing_mode).to_px();
|
||||
let bottom_margin = fragment.margin.bottom(fragment.style.writing_mode).to_px();
|
||||
let right_margin = fragment.margin.right(fragment.style.writing_mode).to_px();
|
||||
let margin = Rect::new(Point2D::new(left_margin, top_margin),
|
||||
Size2D::new(right_margin, bottom_margin));
|
||||
self.union_rect = self.union_rect.union(&margin).union(&padding);
|
||||
}
|
||||
None => {
|
||||
self.level = Some(level);
|
||||
self.is_child = true;
|
||||
self.overflow_direction = overflow_direction(&fragment.style.writing_mode);
|
||||
self.origin_rect = Rect::new(Point2D::new(top_padding, left_padding),
|
||||
Size2D::new(right_padding, bottom_padding));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn should_process(&mut self, fragment: &Fragment) -> bool {
|
||||
fragment.contains_node(self.node_address) || self.is_child
|
||||
}
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
|
||||
impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
|
||||
fn process(&mut self, fragment: &Fragment, level: i32, border_box: &Rect<Au>) {
|
||||
|
@ -400,6 +497,36 @@ pub fn process_node_geometry_request<'ln, N: LayoutNode<'ln>>(requested_node: N,
|
|||
iterator.client_rect
|
||||
}
|
||||
|
||||
pub fn process_node_scroll_area_request<'ln, N: LayoutNode<'ln>>(requested_node: N, layout_root: &mut FlowRef)
|
||||
-> Rect<i32> {
|
||||
let mut iterator = UnioningFragmentScrollAreaIterator::new(requested_node.opaque());
|
||||
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
|
||||
match iterator.overflow_direction {
|
||||
OverflowDirection::RightAndDown => {
|
||||
let right = max(iterator.union_rect.size.width, iterator.origin_rect.size.width);
|
||||
let bottom = max(iterator.union_rect.size.height, iterator.origin_rect.size.height);
|
||||
Rect::new(iterator.origin_rect.origin, Size2D::new(right, bottom))
|
||||
},
|
||||
OverflowDirection::LeftAndDown => {
|
||||
let bottom = max(iterator.union_rect.size.height, iterator.origin_rect.size.height);
|
||||
let left = max(iterator.union_rect.origin.x, iterator.origin_rect.origin.x);
|
||||
Rect::new(Point2D::new(left, iterator.origin_rect.origin.y),
|
||||
Size2D::new(iterator.origin_rect.size.width, bottom))
|
||||
},
|
||||
OverflowDirection::LeftAndUp => {
|
||||
let top = min(iterator.union_rect.origin.y, iterator.origin_rect.origin.y);
|
||||
let left = min(iterator.union_rect.origin.x, iterator.origin_rect.origin.x);
|
||||
Rect::new(Point2D::new(left, top), iterator.origin_rect.size)
|
||||
},
|
||||
OverflowDirection::RightAndUp => {
|
||||
let top = min(iterator.union_rect.origin.y, iterator.origin_rect.origin.y);
|
||||
let right = max(iterator.union_rect.size.width, iterator.origin_rect.size.width);
|
||||
Rect::new(Point2D::new(iterator.origin_rect.origin.x, top),
|
||||
Size2D::new(right, iterator.origin_rect.size.height))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the resolved value of property for a given (pseudo)element.
|
||||
/// https://drafts.csswg.org/cssom/#resolved-value
|
||||
pub fn process_resolved_style_request<'ln, N: LayoutNode<'ln>>(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue