Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trigger reflow on document.elementsFromPoint #15768

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/layout/lib.rs
Expand Up @@ -73,7 +73,7 @@ mod linked_list;
mod list_item;
mod model;
mod multicol;
mod opaque_node;
pub mod opaque_node;
pub mod parallel;
mod persistent_list;
pub mod query;
Expand Down
38 changes: 9 additions & 29 deletions components/layout/query.rs
Expand Up @@ -94,6 +94,9 @@ pub struct LayoutThreadData {

/// A list of images requests that need to be initiated.
pub pending_images: Vec<PendingImage>,

/// A queued response for the list of nodes at a given point.
pub nodes_from_point_response: Vec<UntrustedNodeAddress>,
}

pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutThreadData>>);
Expand Down Expand Up @@ -144,33 +147,10 @@ impl LayoutRPC for LayoutRPCImpl {
}
}

fn nodes_from_point(&self,
page_point: Point2D<f32>,
client_point: Point2D<f32>) -> Vec<UntrustedNodeAddress> {
let page_point = Point2D::new(Au::from_f32_px(page_point.x),
Au::from_f32_px(page_point.y));
let client_point = Point2D::new(Au::from_f32_px(client_point.x),
Au::from_f32_px(client_point.y));

let nodes_from_point_list = {
let &LayoutRPCImpl(ref rw_data) = self;
let rw_data = rw_data.lock().unwrap();
let result = match rw_data.display_list {
None => panic!("Tried to hit test without a DisplayList"),
Some(ref display_list) => {
display_list.hit_test(&page_point,
&client_point,
&rw_data.stacking_context_scroll_offsets)
}
};

result
};

nodes_from_point_list.iter()
.rev()
.map(|metadata| metadata.node.to_untrusted_node_address())
.collect()
fn nodes_from_point_response(&self) -> Vec<UntrustedNodeAddress> {
let &LayoutRPCImpl(ref rw_data) = self;
let rw_data = rw_data.lock().unwrap();
rw_data.nodes_from_point_response.clone()
}

fn node_geometry(&self) -> NodeGeometryResponse {
Expand All @@ -193,8 +173,8 @@ impl LayoutRPC for LayoutRPCImpl {

fn node_scroll_root_id(&self) -> NodeScrollRootIdResponse {
NodeScrollRootIdResponse(self.0.lock()
.unwrap().scroll_root_id_response
.expect("scroll_root_id is not correctly fetched"))
.unwrap().scroll_root_id_response
.expect("scroll_root_id is not correctly fetched"))
}

/// Retrieves the resolved value for a CSS style property.
Expand Down
31 changes: 30 additions & 1 deletion components/layout_thread/lib.rs
Expand Up @@ -63,6 +63,7 @@ use layout::flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwne
use layout::flow_ref::FlowRef;
use layout::incremental::{LayoutDamageComputation, REFLOW_ENTIRE_DOCUMENT};
use layout::layout_debug;
use layout::opaque_node::OpaqueNodeMethods;
use layout::parallel;
use layout::query::{LayoutRPCImpl, LayoutThreadData, process_content_box_request, process_content_boxes_request};
use layout::query::{process_margin_style_query, process_node_overflow_request, process_resolved_style_request};
Expand Down Expand Up @@ -459,6 +460,7 @@ impl LayoutThread {
stacking_context_scroll_offsets: HashMap::new(),
text_index_response: TextIndexResponse(None),
pending_images: vec![],
nodes_from_point_response: vec![],
})),
error_reporter: CSSErrorReporter {
pipelineid: id,
Expand Down Expand Up @@ -977,6 +979,9 @@ impl LayoutThread {
ReflowQueryType::HitTestQuery(..) => {
rw_data.hit_test_response = (None, false);
},
ReflowQueryType::NodesFromPoint(..) => {
rw_data.nodes_from_point_response = Vec::new();
},
ReflowQueryType::NodeGeometryQuery(_) => {
rw_data.client_rect_response = Rect::zero();
},
Expand Down Expand Up @@ -1279,6 +1284,29 @@ impl LayoutThread {
let node = unsafe { ServoLayoutNode::new(&node) };
rw_data.margin_style_response = process_margin_style_query(node);
},
ReflowQueryType::NodesFromPoint(page_point, client_point) => {
let page_point = Point2D::new(Au::from_f32_px(page_point.x),
Au::from_f32_px(page_point.y));
let client_point = Point2D::new(Au::from_f32_px(client_point.x),
Au::from_f32_px(client_point.y));
let nodes_from_point_list = {
let result = match rw_data.display_list {
None => panic!("Tried to hit test without a DisplayList"),
Some(ref display_list) => {
display_list.hit_test(&page_point,
&client_point,
&rw_data.stacking_context_scroll_offsets)
}
};

result
};

rw_data.nodes_from_point_response = nodes_from_point_list.iter()
.rev()
.map(|metadata| metadata.node.to_untrusted_node_address())
.collect()
},
ReflowQueryType::NoQuery => {}
}
}
Expand Down Expand Up @@ -1585,7 +1613,8 @@ fn get_ua_stylesheets() -> Result<UserAgentStylesheets, &'static str> {
/// or false if it only needs stacking-relative positions.
fn reflow_query_type_needs_display_list(query_type: &ReflowQueryType) -> bool {
match *query_type {
ReflowQueryType::HitTestQuery(..) | ReflowQueryType::TextIndexQuery(..) => true,
ReflowQueryType::HitTestQuery(..) | ReflowQueryType::TextIndexQuery(..) |
ReflowQueryType::NodesFromPoint(..) => true,
ReflowQueryType::ContentBoxQuery(_) | ReflowQueryType::ContentBoxesQuery(_) |
ReflowQueryType::NodeGeometryQuery(_) | ReflowQueryType::NodeScrollGeometryQuery(_) |
ReflowQueryType::NodeOverflowQuery(_) | ReflowQueryType::NodeScrollRootIdQuery(_) |
Expand Down
8 changes: 7 additions & 1 deletion components/script/dom/document.rs
Expand Up @@ -1877,7 +1877,13 @@ impl Document {
Point2D::new(client_point.x + self.window.PageXOffset() as f32,
client_point.y + self.window.PageYOffset() as f32);

self.window.layout().nodes_from_point(page_point, *client_point)
if !self.window.reflow(ReflowGoal::ForScriptQuery,
ReflowQueryType::NodesFromPoint(page_point, *client_point),
ReflowReason::Query) {
return vec!();
};

self.window.layout().nodes_from_point_response()
}
}

Expand Down
1 change: 1 addition & 0 deletions components/script/dom/window.rs
Expand Up @@ -1811,6 +1811,7 @@ fn debug_reflow_events(id: PipelineId, goal: &ReflowGoal, query_type: &ReflowQue
ReflowQueryType::ContentBoxQuery(_n) => "\tContentBoxQuery",
ReflowQueryType::ContentBoxesQuery(_n) => "\tContentBoxesQuery",
ReflowQueryType::HitTestQuery(..) => "\tHitTestQuery",
ReflowQueryType::NodesFromPoint(..) => "\tNodesFromPoint",
ReflowQueryType::NodeGeometryQuery(_n) => "\tNodeGeometryQuery",
ReflowQueryType::NodeOverflowQuery(_n) => "\tNodeOverFlowQuery",
ReflowQueryType::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery",
Expand Down
1 change: 1 addition & 0 deletions components/script_layout_interface/message.rs
Expand Up @@ -101,6 +101,7 @@ pub enum ReflowQueryType {
OffsetParentQuery(TrustedNodeAddress),
MarginStyleQuery(TrustedNodeAddress),
TextIndexQuery(TrustedNodeAddress, i32, i32),
NodesFromPoint(Point2D<f32>, Point2D<f32>),
}

/// Information needed for a reflow.
Expand Down
3 changes: 2 additions & 1 deletion components/script_layout_interface/rpc.rs
Expand Up @@ -40,7 +40,8 @@ pub trait LayoutRPC {
fn margin_style(&self) -> MarginStyleResponse;
/// Requests the list of not-yet-loaded images that were encountered in the last reflow.
fn pending_images(&self) -> Vec<PendingImage>;
fn nodes_from_point(&self, page_point: Point2D<f32>, client_point: Point2D<f32>) -> Vec<UntrustedNodeAddress>;
/// Requests the list of nodes from the given point.
fn nodes_from_point_response(&self) -> Vec<UntrustedNodeAddress>;

fn text_index(&self) -> TextIndexResponse;
}
Expand Down
10 changes: 10 additions & 0 deletions tests/wpt/mozilla/meta/MANIFEST.json
Expand Up @@ -12598,6 +12598,12 @@
{}
]
],
"mozilla/document_elementsFromPoint.html": [
[
"/_mozilla/mozilla/document_elementsFromPoint.html",
{}
]
],
"mozilla/document_getElementById.html": [
[
"/_mozilla/mozilla/document_getElementById.html",
Expand Down Expand Up @@ -25137,6 +25143,10 @@
"12eef74e9ba1a62b0302df79633cab5c48f4977f",
"testharness"
],
"mozilla/document_elementsFromPoint.html": [
"00da2141b1143619351c6fbb66d677ca9002a4a8",
"testharness"
],
"mozilla/document_getElementById.html": [
"ae5270afde878c8fbe9b4a89c5c3f8ff609220dc",
"testharness"
Expand Down
10 changes: 10 additions & 0 deletions tests/wpt/mozilla/tests/mozilla/document_elementsFromPoint.html
@@ -0,0 +1,10 @@
<!doctype html>
<meta charset="utf-8">
<title>document.elementsFromPoint does not crash due to a missing display list</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
test(function() {
document.elementsFromPoint(10, 10);
}, "doesn't crash");
</script>