servo: Merge #16865 - Properly handle scroll offsets in hit testing (from mrobinson:scroll-offsets-fix); r=emilio

Scroll roots are no longer nested containers holding items, so instead
we need to track the offsets of each, carefully handling fixed position
items and stacking contexts that create new reference frames.
Additionally, we remove the complexity of the pre-computed page scroll
offset, instead opting to send script scrolls to the layout task in
order to more quickly have a ScrollState there that matches the
script's idea of the scroll world.

Fixes #16405.

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #16405.

<!-- Either: -->
- [ ] There are tests for these changes OR
- [x] These changes do not require tests because it is currently impossible to test interactive scrolling with Servo's test infrastructure. Existing tests verify the script part though.

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

Source-Repo: https://github.com/servo/servo
Source-Revision: d855c929ef32e8f7d4bc15ba726e8eb5f8ad8e05

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : c4b92e4eab5b1712a84c4437f483ededcf317794
This commit is contained in:
Martin Robinson 2017-05-16 08:33:22 -05:00
Родитель f13a8dc7cc
Коммит 5f37c2fc81
8 изменённых файлов: 221 добавлений и 178 удалений

Просмотреть файл

@ -22,7 +22,7 @@ use net_traits::image::base::{Image, PixelFormat};
use profile_traits::time::{self, ProfilerCategory, profile};
use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg};
use script_traits::{ConstellationMsg, DevicePixel, LayoutControlMsg, LoadData, MouseButton};
use script_traits::{MouseEventType, StackingContextScrollState};
use script_traits::{MouseEventType, ScrollState};
use script_traits::{TouchpadPressurePhase, TouchEventType, TouchId, WindowSizeData, WindowSizeType};
use script_traits::CompositorEvent::{self, MouseMoveEvent, MouseButtonEvent, TouchEvent, TouchpadPressureEvent};
use servo_config::opts;
@ -1368,29 +1368,26 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
fn send_viewport_rects(&self) {
let mut stacking_context_scroll_states_per_pipeline = HashMap::new();
let mut scroll_states_per_pipeline = HashMap::new();
for scroll_layer_state in self.webrender_api.get_scroll_node_state() {
if scroll_layer_state.id.external_id().is_none() &&
scroll_layer_state.id.is_root_scroll_node() {
!scroll_layer_state.id.is_root_scroll_node() {
continue;
}
let stacking_context_scroll_state = StackingContextScrollState {
let scroll_state = ScrollState {
scroll_root_id: scroll_layer_state.id,
scroll_offset: scroll_layer_state.scroll_offset.to_untyped(),
};
stacking_context_scroll_states_per_pipeline
.entry(scroll_layer_state.id.pipeline_id())
.or_insert(vec![])
.push(stacking_context_scroll_state);
scroll_states_per_pipeline.entry(scroll_layer_state.id.pipeline_id())
.or_insert(vec![])
.push(scroll_state);
}
for (pipeline_id, stacking_context_scroll_states) in
stacking_context_scroll_states_per_pipeline {
for (pipeline_id, scroll_states) in scroll_states_per_pipeline {
if let Some(pipeline) = self.pipeline(pipeline_id.from_webrender()) {
let msg = LayoutControlMsg::SetStackingContextScrollStates(
stacking_context_scroll_states);
let msg = LayoutControlMsg::SetScrollStates(scroll_states);
let _ = pipeline.layout_chan.send(msg);
}
}

Просмотреть файл

@ -47,6 +47,74 @@ pub struct DisplayList {
pub list: Vec<DisplayItem>,
}
struct ScrollOffsetLookup<'a> {
parents: &'a mut HashMap<ClipId, ClipId>,
calculated_total_offsets: ScrollOffsetMap,
raw_offsets: &'a ScrollOffsetMap,
}
impl<'a> ScrollOffsetLookup<'a> {
fn new(parents: &'a mut HashMap<ClipId, ClipId>,
raw_offsets: &'a ScrollOffsetMap)
-> ScrollOffsetLookup<'a> {
ScrollOffsetLookup {
parents: parents,
calculated_total_offsets: HashMap::new(),
raw_offsets: raw_offsets,
}
}
fn new_for_reference_frame(&mut self,
clip_id: ClipId,
transform: &Matrix4D<f32>,
point: &mut Point2D<Au>)
-> Option<ScrollOffsetLookup> {
// If a transform function causes the current transformation matrix of an object
// to be non-invertible, the object and its content do not get displayed.
let inv_transform = match transform.inverse() {
Some(transform) => transform,
None => return None,
};
let scroll_offset = self.full_offset_for_scroll_root(&clip_id);
*point = Point2D::new(point.x - Au::from_f32_px(scroll_offset.x),
point.y - Au::from_f32_px(scroll_offset.y));
let frac_point = inv_transform.transform_point(&Point2D::new(point.x.to_f32_px(),
point.y.to_f32_px()));
*point = Point2D::new(Au::from_f32_px(frac_point.x), Au::from_f32_px(frac_point.y));
let mut sublookup = ScrollOffsetLookup {
parents: &mut self.parents,
calculated_total_offsets: HashMap::new(),
raw_offsets: self.raw_offsets,
};
sublookup.calculated_total_offsets.insert(clip_id, Point2D::zero());
Some(sublookup)
}
fn add_scroll_root(&mut self, scroll_root: &ScrollRoot) {
self.parents.insert(scroll_root.id, scroll_root.parent_id);
}
fn full_offset_for_scroll_root(&mut self, id: &ClipId) -> Point2D<f32> {
if let Some(offset) = self.calculated_total_offsets.get(id) {
return *offset;
}
let parent_offset = if !id.is_root_scroll_node() {
let parent_id = *self.parents.get(id).unwrap();
self.full_offset_for_scroll_root(&parent_id)
} else {
Point2D::zero()
};
let offset = parent_offset +
self.raw_offsets.get(id).cloned().unwrap_or_else(Point2D::zero);
self.calculated_total_offsets.insert(*id, offset);
offset
}
}
impl DisplayList {
/// Return the bounds of this display list based on the dimensions of the root
/// stacking context.
@ -69,51 +137,36 @@ impl DisplayList {
self.text_index_contents(node,
&mut traversal,
client_point,
client_point,
scroll_offsets,
&mut ScrollOffsetLookup::new(&mut HashMap::new(), scroll_offsets),
&mut result);
result.pop()
}
pub fn text_index_contents<'a>(&self,
node: OpaqueNode,
traversal: &mut DisplayListTraversal<'a>,
translated_point: &Point2D<Au>,
client_point: &Point2D<Au>,
scroll_offsets: &ScrollOffsetMap,
result: &mut Vec<usize>) {
fn text_index_contents<'a>(&self,
node: OpaqueNode,
traversal: &mut DisplayListTraversal<'a>,
point: &Point2D<Au>,
offset_lookup: &mut ScrollOffsetLookup,
result: &mut Vec<usize>) {
while let Some(item) = traversal.next() {
match item {
&DisplayItem::PushStackingContext(ref stacking_context_item) => {
let mut point = *translated_point;
DisplayList::translate_point(&stacking_context_item.stacking_context,
&mut point,
client_point);
self.text_index_contents(node,
traversal,
&point,
client_point,
scroll_offsets,
result);
&DisplayItem::PushStackingContext(ref context_item) => {
self.text_index_stacking_context(&context_item.stacking_context,
item.base().scroll_root_id,
node,
traversal,
point,
offset_lookup,
result);
}
&DisplayItem::DefineClip(ref item) => {
let mut point = *translated_point;
DisplayList::scroll_root(&item.scroll_root,
&mut point,
scroll_offsets);
self.text_index_contents(node,
traversal,
&point,
client_point,
scroll_offsets,
result);
},
offset_lookup.add_scroll_root(&item.scroll_root);
}
&DisplayItem::PopStackingContext(_) => return,
&DisplayItem::Text(ref text) => {
let base = item.base();
if base.metadata.node == node {
let offset = *translated_point - text.baseline_origin;
let offset = *point - text.baseline_origin;
let index = text.text_run.range_index_of_advance(&text.range, offset.x);
result.push(index);
}
@ -123,56 +176,71 @@ impl DisplayList {
}
}
fn text_index_stacking_context<'a>(&self,
stacking_context: &StackingContext,
clip_id: ClipId,
node: OpaqueNode,
traversal: &mut DisplayListTraversal<'a>,
point: &Point2D<Au>,
offset_lookup: &mut ScrollOffsetLookup,
result: &mut Vec<usize>) {
let mut point = *point - stacking_context.bounds.origin;
if stacking_context.scroll_policy == ScrollPolicy::Fixed {
let old_offset = offset_lookup.calculated_total_offsets.get(&clip_id).cloned();
offset_lookup.calculated_total_offsets.insert(clip_id, Point2D::zero());
self.text_index_contents(node, traversal, &point, offset_lookup, result);
match old_offset {
Some(offset) => offset_lookup.calculated_total_offsets.insert(clip_id, offset),
None => offset_lookup.calculated_total_offsets.remove(&clip_id),
};
} else if let Some(transform) = stacking_context.transform {
if let Some(ref mut sublookup) =
offset_lookup.new_for_reference_frame(clip_id, &transform, &mut point) {
self.text_index_contents(node, traversal, &point, sublookup, result);
}
} else {
self.text_index_contents(node, traversal, &point, offset_lookup, result);
}
}
// Return all nodes containing the point of interest, bottommost first, and
// respecting the `pointer-events` CSS property.
pub fn hit_test(&self,
translated_point: &Point2D<Au>,
client_point: &Point2D<Au>,
point: &Point2D<Au>,
scroll_offsets: &ScrollOffsetMap)
-> Vec<DisplayItemMetadata> {
let mut result = Vec::new();
let mut traversal = DisplayListTraversal::new(self);
self.hit_test_contents(&mut traversal,
translated_point,
client_point,
scroll_offsets,
point,
&mut ScrollOffsetLookup::new(&mut HashMap::new(), scroll_offsets),
&mut result);
result
}
pub fn hit_test_contents<'a>(&self,
traversal: &mut DisplayListTraversal<'a>,
translated_point: &Point2D<Au>,
client_point: &Point2D<Au>,
scroll_offsets: &ScrollOffsetMap,
result: &mut Vec<DisplayItemMetadata>) {
fn hit_test_contents<'a>(&self,
traversal: &mut DisplayListTraversal<'a>,
point: &Point2D<Au>,
offset_lookup: &mut ScrollOffsetLookup,
result: &mut Vec<DisplayItemMetadata>) {
while let Some(item) = traversal.next() {
match item {
&DisplayItem::PushStackingContext(ref stacking_context_item) => {
let mut point = *translated_point;
DisplayList::translate_point(&stacking_context_item.stacking_context,
&mut point,
client_point);
self.hit_test_contents(traversal,
&point,
client_point,
scroll_offsets,
result);
}
&DisplayItem::DefineClip(ref item) => {
let mut point = *translated_point;
DisplayList::scroll_root(&item.scroll_root,
&mut point,
scroll_offsets);
self.hit_test_contents(traversal,
&point,
client_point,
scroll_offsets,
result);
&DisplayItem::PushStackingContext(ref context_item) => {
self.hit_test_stacking_context(&context_item.stacking_context,
item.base().scroll_root_id,
traversal,
point,
offset_lookup,
result);
}
&DisplayItem::PopStackingContext(_) => return,
&DisplayItem::DefineClip(ref item) => {
offset_lookup.add_scroll_root(&item.scroll_root);
}
_ => {
if let Some(meta) = item.hit_test(*translated_point) {
if let Some(meta) = item.hit_test(*point, offset_lookup) {
result.push(meta);
}
}
@ -180,52 +248,33 @@ impl DisplayList {
}
}
#[inline]
fn translate_point<'a>(stacking_context: &StackingContext,
translated_point: &mut Point2D<Au>,
client_point: &Point2D<Au>) {
// Convert the parent translated point into stacking context local transform space if the
// stacking context isn't fixed. If it's fixed, we need to use the client point anyway.
fn hit_test_stacking_context<'a>(&self,
stacking_context: &StackingContext,
clip_id: ClipId,
traversal: &mut DisplayListTraversal<'a>,
point: &Point2D<Au>,
offset_lookup: &mut ScrollOffsetLookup,
result: &mut Vec<DisplayItemMetadata>) {
debug_assert!(stacking_context.context_type == StackingContextType::Real);
let is_fixed = stacking_context.scroll_policy == ScrollPolicy::Fixed;
*translated_point = if is_fixed {
*client_point
} else {
let point = *translated_point - stacking_context.bounds.origin;
match stacking_context.transform {
Some(transform) => {
let inv_transform = match transform.inverse() {
Some(transform) => transform,
None => {
// If a transform function causes the current transformation matrix of an object
// to be non-invertible, the object and its content do not get displayed.
return;
}
};
let frac_point = inv_transform.transform_point(&Point2D::new(point.x.to_f32_px(),
point.y.to_f32_px()));
Point2D::new(Au::from_f32_px(frac_point.x), Au::from_f32_px(frac_point.y))
}
None => {
point
}
let mut point = *point - stacking_context.bounds.origin;
if stacking_context.scroll_policy == ScrollPolicy::Fixed {
let old_offset = offset_lookup.calculated_total_offsets.get(&clip_id).cloned();
offset_lookup.calculated_total_offsets.insert(clip_id, Point2D::zero());
self.hit_test_contents(traversal, &point, offset_lookup, result);
match old_offset {
Some(offset) => offset_lookup.calculated_total_offsets.insert(clip_id, offset),
None => offset_lookup.calculated_total_offsets.remove(&clip_id),
};
} else if let Some(transform) = stacking_context.transform {
if let Some(ref mut sublookup) =
offset_lookup.new_for_reference_frame(clip_id, &transform, &mut point) {
self.hit_test_contents(traversal, &point, sublookup, result);
}
};
}
#[inline]
fn scroll_root<'a>(scroll_root: &ScrollRoot,
translated_point: &mut Point2D<Au>,
scroll_offsets: &ScrollOffsetMap) {
// Adjust the translated point to account for the scroll offset if necessary.
//
// We don't perform this adjustment on the root stacking context because
// the DOM-side code has already translated the point for us (e.g. in
// `Window::hit_test_query()`) by now.
if let Some(scroll_offset) = scroll_offsets.get(&scroll_root.id) {
translated_point.x -= Au::from_f32_px(scroll_offset.x);
translated_point.y -= Au::from_f32_px(scroll_offset.y);
} else {
self.hit_test_contents(traversal, &point, offset_lookup, result);
}
}
@ -1207,11 +1256,18 @@ impl DisplayItem {
println!("{}+ {:?}", indent, self);
}
fn hit_test(&self, point: Point2D<Au>) -> Option<DisplayItemMetadata> {
fn hit_test(&self,
point: Point2D<Au>,
offset_lookup: &mut ScrollOffsetLookup)
-> Option<DisplayItemMetadata> {
// TODO(pcwalton): Use a precise algorithm here. This will allow us to properly hit
// test elements with `border-radius`, for example.
let base_item = self.base();
let scroll_offset = offset_lookup.full_offset_for_scroll_root(&base_item.scroll_root_id);
let point = Point2D::new(point.x - Au::from_f32_px(scroll_offset.x),
point.y - Au::from_f32_px(scroll_offset.y));
if !base_item.clip.might_intersect_point(&point) {
// Clipped out.
return None;

Просмотреть файл

@ -81,8 +81,8 @@ pub struct LayoutThreadData {
/// A queued response for the offset parent/rect of a node.
pub margin_style_response: MarginStyleResponse,
/// Scroll offsets of stacking contexts. This will only be populated if WebRender is in use.
pub stacking_context_scroll_offsets: ScrollOffsetMap,
/// Scroll offsets of scrolling regions.
pub scroll_offsets: ScrollOffsetMap,
/// Index in a text fragment. We need this do determine the insertion point.
pub text_index_response: TextIndexResponse,

Просмотреть файл

@ -88,7 +88,7 @@ use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowR
use script_layout_interface::rpc::TextIndexResponse;
use script_layout_interface::wrapper_traits::LayoutNode;
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
use script_traits::{StackingContextScrollState, UntrustedNodeAddress};
use script_traits::{ScrollState, UntrustedNodeAddress};
use selectors::Element;
use servo_config::opts;
use servo_config::prefs::PREFS;
@ -506,7 +506,7 @@ impl LayoutThread {
resolved_style_response: String::new(),
offset_parent_response: OffsetParentResponse::empty(),
margin_style_response: MarginStyleResponse::empty(),
stacking_context_scroll_offsets: HashMap::new(),
scroll_offsets: HashMap::new(),
text_index_response: TextIndexResponse(None),
nodes_from_point_response: vec![],
})),
@ -600,9 +600,8 @@ impl LayoutThread {
};
match request {
Request::FromPipeline(LayoutControlMsg::SetStackingContextScrollStates(
new_scroll_states)) => {
self.handle_request_helper(Msg::SetStackingContextScrollStates(new_scroll_states),
Request::FromPipeline(LayoutControlMsg::SetScrollStates(new_scroll_states)) => {
self.handle_request_helper(Msg::SetScrollStates(new_scroll_states),
possibly_locked_rw_data)
},
Request::FromPipeline(LayoutControlMsg::TickAnimations) => {
@ -653,9 +652,12 @@ impl LayoutThread {
|| self.handle_reflow(&mut data, possibly_locked_rw_data));
},
Msg::TickAnimations => self.tick_all_animations(possibly_locked_rw_data),
Msg::SetStackingContextScrollStates(new_scroll_states) => {
self.set_stacking_context_scroll_states(new_scroll_states,
possibly_locked_rw_data);
Msg::SetScrollStates(new_scroll_states) => {
self.set_scroll_states(new_scroll_states, possibly_locked_rw_data);
}
Msg::UpdateScrollStateFromScript(state) => {
let mut rw_data = possibly_locked_rw_data.lock();
rw_data.scroll_offsets.insert(state.scroll_root_id, state.scroll_offset);
}
Msg::ReapStyleAndLayoutData(dead_data) => {
unsafe {
@ -1306,19 +1308,13 @@ impl LayoutThread {
let node = unsafe { ServoLayoutNode::new(&node) };
rw_data.content_boxes_response = process_content_boxes_request(node, root_flow);
},
ReflowQueryType::HitTestQuery(translated_point, client_point, update_cursor) => {
let mut translated_point = Point2D::new(Au::from_f32_px(translated_point.x),
Au::from_f32_px(translated_point.y));
let client_point = Point2D::new(Au::from_f32_px(client_point.x),
Au::from_f32_px(client_point.y));
ReflowQueryType::HitTestQuery(client_point, update_cursor) => {
let point = Point2D::new(Au::from_f32_px(client_point.x),
Au::from_f32_px(client_point.y));
let result = rw_data.display_list
.as_ref()
.expect("Tried to hit test with no display list")
.hit_test(&mut translated_point,
&client_point,
&rw_data.stacking_context_scroll_offsets);
.hit_test(&point, &rw_data.scroll_offsets);
rw_data.hit_test_response = (result.last().cloned(), update_cursor);
},
ReflowQueryType::TextIndexQuery(node, mouse_x, mouse_y) => {
@ -1332,7 +1328,7 @@ impl LayoutThread {
.expect("Tried to hit test with no display list")
.text_index(opaque_node,
&client_point,
&rw_data.stacking_context_scroll_offsets));
&rw_data.scroll_offsets));
},
ReflowQueryType::NodeGeometryQuery(node) => {
let node = unsafe { ServoLayoutNode::new(&node) };
@ -1368,18 +1364,14 @@ 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));
ReflowQueryType::NodesFromPoint(client_point) => {
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)
display_list.hit_test(&client_point, &rw_data.scroll_offsets)
}
};
@ -1395,10 +1387,9 @@ impl LayoutThread {
}
}
fn set_stacking_context_scroll_states<'a, 'b>(
&mut self,
new_scroll_states: Vec<StackingContextScrollState>,
possibly_locked_rw_data: &mut RwData<'a, 'b>) {
fn set_scroll_states<'a, 'b>(&mut self,
new_scroll_states: Vec<ScrollState>,
possibly_locked_rw_data: &mut RwData<'a, 'b>) {
let mut rw_data = possibly_locked_rw_data.lock();
let mut script_scroll_states = vec![];
let mut layout_scroll_states = HashMap::new();
@ -1416,7 +1407,7 @@ impl LayoutThread {
}
let _ = self.script_chan
.send(ConstellationControlMsg::SetScrollState(self.id, script_scroll_states));
rw_data.stacking_context_scroll_offsets = layout_scroll_states
rw_data.scroll_offsets = layout_scroll_states
}
fn tick_all_animations<'a, 'b>(&mut self, possibly_locked_rw_data: &mut RwData<'a, 'b>) {

Просмотреть файл

@ -1955,12 +1955,8 @@ impl Document {
}
pub fn nodes_from_point(&self, client_point: &Point2D<f32>) -> Vec<UntrustedNodeAddress> {
let page_point =
Point2D::new(client_point.x + self.window.PageXOffset() as f32,
client_point.y + self.window.PageYOffset() as f32);
if !self.window.reflow(ReflowGoal::ForScriptQuery,
ReflowQueryType::NodesFromPoint(page_point, *client_point),
ReflowQueryType::NodesFromPoint(*client_point),
ReflowReason::Query) {
return vec!();
};

Просмотреть файл

@ -75,11 +75,11 @@ use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, Lay
use script_layout_interface::rpc::{MarginStyleResponse, NodeScrollRootIdResponse};
use script_layout_interface::rpc::{ResolvedStyleResponse, TextIndexResponse};
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThreadEventCategory};
use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, RunnableWrapper};
use script_thread::{SendableMainThreadScriptChan, ImageCacheMsg, ScriptThread};
use script_traits::{ConstellationControlMsg, LoadData, MozBrowserEvent, UntrustedNodeAddress};
use script_traits::{DocumentState, TimerEvent, TimerEventId};
use script_traits::{ScriptMsg as ConstellationMsg, TimerSchedulerMsg, WindowSizeData, WindowSizeType};
use script_thread::{ImageCacheMsg, MainThreadScriptChan, MainThreadScriptMsg, Runnable};
use script_thread::{RunnableWrapper, ScriptThread, SendableMainThreadScriptChan};
use script_traits::{ConstellationControlMsg, DocumentState, LoadData, MozBrowserEvent};
use script_traits::{ScriptMsg as ConstellationMsg, ScrollState, TimerEvent, TimerEventId};
use script_traits::{TimerSchedulerMsg, UntrustedNodeAddress, WindowSizeData, WindowSizeType};
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
use servo_atoms::Atom;
use servo_config::opts;
@ -1111,6 +1111,11 @@ impl Window {
ScrollBehavior::Smooth => true
};
self.layout_chan.send(Msg::UpdateScrollStateFromScript(ScrollState {
scroll_root_id: scroll_root_id,
scroll_offset: Point2D::new(-x, -y),
})).unwrap();
// TODO (farodin91): Raise an event to stop the current_viewport
self.update_viewport_for_scroll(x, y);
@ -1372,14 +1377,8 @@ impl Window {
client_point: Point2D<f32>,
update_cursor: bool)
-> Option<UntrustedNodeAddress> {
let translated_point =
Point2D::new(client_point.x + self.PageXOffset() as f32,
client_point.y + self.PageYOffset() as f32);
if !self.reflow(ReflowGoal::ForScriptQuery,
ReflowQueryType::HitTestQuery(translated_point,
client_point,
update_cursor),
ReflowQueryType::HitTestQuery(client_point, update_cursor),
ReflowReason::Query) {
return None
}

Просмотреть файл

@ -12,8 +12,8 @@ use msg::constellation_msg::PipelineId;
use net_traits::image_cache::ImageCache;
use profile_traits::mem::ReportsChan;
use rpc::LayoutRPC;
use script_traits::{ConstellationControlMsg, LayoutControlMsg, UntrustedNodeAddress};
use script_traits::{LayoutMsg as ConstellationMsg, StackingContextScrollState, WindowSizeData};
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
use script_traits::{ScrollState, UntrustedNodeAddress, WindowSizeData};
use servo_url::ServoUrl;
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender};
@ -79,7 +79,11 @@ pub enum Msg {
SetFinalUrl(ServoUrl),
/// Tells layout about the new scrolling offsets of each scrollable stacking context.
SetStackingContextScrollStates(Vec<StackingContextScrollState>),
SetScrollStates(Vec<ScrollState>),
/// Tells layout about a single new scrolling offset from the script. The rest will
/// remain untouched and layout won't forward this back to script.
UpdateScrollStateFromScript(ScrollState),
}
@ -90,7 +94,7 @@ pub enum ReflowQueryType {
ContentBoxQuery(TrustedNodeAddress),
ContentBoxesQuery(TrustedNodeAddress),
NodeOverflowQuery(TrustedNodeAddress),
HitTestQuery(Point2D<f32>, Point2D<f32>, bool),
HitTestQuery(Point2D<f32>, bool),
NodeScrollRootIdQuery(TrustedNodeAddress),
NodeGeometryQuery(TrustedNodeAddress),
NodeScrollGeometryQuery(TrustedNodeAddress),
@ -98,7 +102,7 @@ pub enum ReflowQueryType {
OffsetParentQuery(TrustedNodeAddress),
MarginStyleQuery(TrustedNodeAddress),
TextIndexQuery(TrustedNodeAddress, i32, i32),
NodesFromPoint(Point2D<f32>, Point2D<f32>),
NodesFromPoint(Point2D<f32>),
}
/// Information needed for a reflow.

Просмотреть файл

@ -122,7 +122,7 @@ pub enum LayoutControlMsg {
/// Asks layout to run another step in its animation.
TickAnimations,
/// Tells layout about the new scrolling offsets of each scrollable stacking context.
SetStackingContextScrollStates(Vec<StackingContextScrollState>),
SetScrollStates(Vec<ScrollState>),
/// Requests the current load state of Web fonts. `true` is returned if fonts are still loading
/// and `false` is returned if all fonts have loaded.
GetWebFontLoadState(IpcSender<bool>),
@ -673,7 +673,7 @@ pub enum AnimationTickType {
/// The scroll state of a stacking context.
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub struct StackingContextScrollState {
pub struct ScrollState {
/// The ID of the scroll root.
pub scroll_root_id: ClipId,
/// The scrolling offset of this stacking context.