зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #15768 - Trigger reflow on document.elementsFromPoint (from ferjm:issue-15592-document-elementsFromPoint); r=emilio
As [suggested](https://github.com/servo/servo/issues/15592#issuecomment-280379805) by @jdm `Document::nodes_from_point` now triggers a reflow. I added a new reftest that panics with `ERROR:servo: Tried to hit test without a DisplayList` if this patch is not applied. - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #15592. - [X] There are tests for these changes Source-Repo: https://github.com/servo/servo Source-Revision: fa32d50c7a2fc9cb29c7245dc45a46ed68551601 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 021cbb5719229eeffbde8abde6a69508cf997f4f
This commit is contained in:
Родитель
5aa1b30f29
Коммит
82f05b739f
|
@ -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;
|
||||
|
|
|
@ -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>>);
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
|
|
@ -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};
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
},
|
||||
|
@ -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 => {}
|
||||
}
|
||||
}
|
||||
|
@ -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(_) |
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче