mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
layout: Make the stacking context take into account the children transform when calculating overflow areas.
This only works for simple translations and similar, but I want Patrick to validate my approach.
This commit is contained in:
parent
49431be44a
commit
fd3a99ead3
5 changed files with 85 additions and 32 deletions
|
@ -360,7 +360,7 @@ impl DisplayList {
|
||||||
return Some(stacking_context);
|
return Some(stacking_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
for kid in stacking_context.children.iter() {
|
for kid in stacking_context.children() {
|
||||||
let result = find_stacking_context_in_stacking_context(kid, stacking_context_id);
|
let result = find_stacking_context_in_stacking_context(kid, stacking_context_id);
|
||||||
if result.is_some() {
|
if result.is_some() {
|
||||||
return result;
|
return result;
|
||||||
|
@ -449,8 +449,9 @@ impl DisplayList {
|
||||||
let old_transform = paint_context.draw_target.get_transform();
|
let old_transform = paint_context.draw_target.get_transform();
|
||||||
let pixels_per_px = paint_context.screen_pixels_per_px();
|
let pixels_per_px = paint_context.screen_pixels_per_px();
|
||||||
let (transform, subpixel_offset) = match stacking_context.layer_info {
|
let (transform, subpixel_offset) = match stacking_context.layer_info {
|
||||||
// If this stacking context starts a layer, the offset and transformation are handled
|
// If this stacking context starts a layer, the offset and
|
||||||
// by layer position within the compositor.
|
// transformation are handled by layer position within the
|
||||||
|
// compositor.
|
||||||
Some(..) => (*transform, *subpixel_offset),
|
Some(..) => (*transform, *subpixel_offset),
|
||||||
None => {
|
None => {
|
||||||
let origin = stacking_context.bounds.origin + *subpixel_offset;
|
let origin = stacking_context.bounds.origin + *subpixel_offset;
|
||||||
|
@ -606,7 +607,7 @@ pub struct StackingContext {
|
||||||
pub layer_info: Option<LayerInfo>,
|
pub layer_info: Option<LayerInfo>,
|
||||||
|
|
||||||
/// Children of this StackingContext.
|
/// Children of this StackingContext.
|
||||||
pub children: Vec<Box<StackingContext>>,
|
children: Vec<Box<StackingContext>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StackingContext {
|
impl StackingContext {
|
||||||
|
@ -642,6 +643,73 @@ impl StackingContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_children(&mut self, children: Vec<Box<StackingContext>>) {
|
||||||
|
debug_assert!(self.children.is_empty());
|
||||||
|
// We need to take into account the possible transformations of the
|
||||||
|
// child stacking contexts.
|
||||||
|
for child in &children {
|
||||||
|
self.update_overflow_for_new_child(&child);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.children = children;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_child(&mut self, child: Box<StackingContext>) {
|
||||||
|
self.update_overflow_for_new_child(&child);
|
||||||
|
self.children.push(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_children(&mut self, children: Vec<Box<StackingContext>>) {
|
||||||
|
if self.children.is_empty() {
|
||||||
|
return self.set_children(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
for child in children {
|
||||||
|
self.add_child(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn child_at_mut(&mut self, index: usize) -> &mut StackingContext {
|
||||||
|
&mut *self.children[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn children(&self) -> &[Box<StackingContext>] {
|
||||||
|
&self.children
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_overflow_for_new_child(&mut self, child: &StackingContext) {
|
||||||
|
if self.context_type == StackingContextType::Real &&
|
||||||
|
child.context_type == StackingContextType::Real &&
|
||||||
|
!self.scrolls_overflow_area {
|
||||||
|
// This child might be transformed, so we need to take into account
|
||||||
|
// its transformed overflow rect too, but at the correct position.
|
||||||
|
let overflow =
|
||||||
|
child.overflow_rect_in_parent_space();
|
||||||
|
|
||||||
|
self.overflow = self.overflow.union(&overflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn overflow_rect_in_parent_space(&self) -> Rect<Au> {
|
||||||
|
// Transform this stacking context to get it into the same space as
|
||||||
|
// the parent stacking context.
|
||||||
|
//
|
||||||
|
// TODO: Take into account 3d transforms, even though it's a fairly
|
||||||
|
// uncommon case.
|
||||||
|
let origin_x = self.bounds.origin.x.to_f32_px();
|
||||||
|
let origin_y = self.bounds.origin.y.to_f32_px();
|
||||||
|
|
||||||
|
let transform = Matrix4D::identity().translate(origin_x, origin_y, 0.0)
|
||||||
|
.mul(&self.transform);
|
||||||
|
let transform_2d = Matrix2D::new(transform.m11, transform.m12,
|
||||||
|
transform.m21, transform.m22,
|
||||||
|
transform.m41, transform.m42);
|
||||||
|
|
||||||
|
let overflow = geometry::au_rect_to_f32_rect(self.overflow);
|
||||||
|
let overflow = transform_2d.transform_rect(&overflow);
|
||||||
|
geometry::f32_rect_to_au_rect(overflow)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn hit_test<'a>(&self,
|
pub fn hit_test<'a>(&self,
|
||||||
traversal: &mut DisplayListTraversal<'a>,
|
traversal: &mut DisplayListTraversal<'a>,
|
||||||
translated_point: &Point2D<Au>,
|
translated_point: &Point2D<Au>,
|
||||||
|
@ -679,7 +747,7 @@ impl StackingContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for child in self.children.iter() {
|
for child in self.children() {
|
||||||
while let Some(item) = traversal.advance(self) {
|
while let Some(item) = traversal.advance(self) {
|
||||||
if let Some(meta) = item.hit_test(point) {
|
if let Some(meta) = item.hit_test(point) {
|
||||||
result.push(meta);
|
result.push(meta);
|
||||||
|
@ -697,13 +765,13 @@ impl StackingContext {
|
||||||
|
|
||||||
pub fn print_with_tree(&self, print_tree: &mut PrintTree) {
|
pub fn print_with_tree(&self, print_tree: &mut PrintTree) {
|
||||||
print_tree.new_level(format!("{:?}", self));
|
print_tree.new_level(format!("{:?}", self));
|
||||||
for kid in self.children.iter() {
|
for kid in self.children() {
|
||||||
kid.print_with_tree(print_tree);
|
kid.print_with_tree(print_tree);
|
||||||
}
|
}
|
||||||
print_tree.end_level();
|
print_tree.end_level();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn intersects_rect_in_parent_context(&self, rect: Option<Rect<Au>>) -> bool {
|
fn intersects_rect_in_parent_context(&self, rect: Option<Rect<Au>>) -> bool {
|
||||||
// We only do intersection checks for real stacking contexts, since
|
// We only do intersection checks for real stacking contexts, since
|
||||||
// pseudo stacking contexts might not have proper position information.
|
// pseudo stacking contexts might not have proper position information.
|
||||||
if self.context_type != StackingContextType::Real {
|
if self.context_type != StackingContextType::Real {
|
||||||
|
@ -715,24 +783,7 @@ impl StackingContext {
|
||||||
None => return true,
|
None => return true,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Transform this stacking context to get it into the same space as
|
self.overflow_rect_in_parent_space().intersects(rect)
|
||||||
// the parent stacking context.
|
|
||||||
let origin_x = self.bounds.origin.x.to_f32_px();
|
|
||||||
let origin_y = self.bounds.origin.y.to_f32_px();
|
|
||||||
|
|
||||||
let transform = Matrix4D::identity().translate(origin_x,
|
|
||||||
origin_y,
|
|
||||||
0.0)
|
|
||||||
.mul(&self.transform);
|
|
||||||
let transform_2d = Matrix2D::new(transform.m11, transform.m12,
|
|
||||||
transform.m21, transform.m22,
|
|
||||||
transform.m41, transform.m42);
|
|
||||||
|
|
||||||
let overflow = geometry::au_rect_to_f32_rect(self.overflow);
|
|
||||||
let overflow = transform_2d.transform_rect(&overflow);
|
|
||||||
let overflow = geometry::f32_rect_to_au_rect(overflow);
|
|
||||||
|
|
||||||
rect.intersects(&overflow)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -254,7 +254,7 @@ impl LayerCreator {
|
||||||
parent_origin: &Point2D<Au>,
|
parent_origin: &Point2D<Au>,
|
||||||
transform: &Matrix4D<f32>,
|
transform: &Matrix4D<f32>,
|
||||||
perspective: &Matrix4D<f32>) {
|
perspective: &Matrix4D<f32>) {
|
||||||
for kid in stacking_context.children.iter() {
|
for kid in stacking_context.children() {
|
||||||
while let Some(item) = traversal.advance(stacking_context) {
|
while let Some(item) = traversal.advance(stacking_context) {
|
||||||
self.create_layers_for_item(item,
|
self.create_layers_for_item(item,
|
||||||
parent_origin,
|
parent_origin,
|
||||||
|
|
|
@ -1729,7 +1729,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contexts[stacking_context_index].children = floating;
|
contexts[stacking_context_index].set_children(floating);
|
||||||
return stacking_context_id;
|
return stacking_context_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1745,14 +1745,14 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
&self.base,
|
&self.base,
|
||||||
scroll_policy,
|
scroll_policy,
|
||||||
StackingContextCreationMode::InnerScrollWrapper);
|
StackingContextCreationMode::InnerScrollWrapper);
|
||||||
inner_stacking_context.children = child_contexts;
|
inner_stacking_context.set_children(child_contexts);
|
||||||
|
|
||||||
let mut outer_stacking_context = self.fragment.create_stacking_context(
|
let mut outer_stacking_context = self.fragment.create_stacking_context(
|
||||||
stacking_context_id,
|
stacking_context_id,
|
||||||
&self.base,
|
&self.base,
|
||||||
scroll_policy,
|
scroll_policy,
|
||||||
StackingContextCreationMode::OuterScrollWrapper);
|
StackingContextCreationMode::OuterScrollWrapper);
|
||||||
outer_stacking_context.children.push(inner_stacking_context);
|
outer_stacking_context.add_child(inner_stacking_context);
|
||||||
outer_stacking_context
|
outer_stacking_context
|
||||||
} else {
|
} else {
|
||||||
let mut stacking_context = self.fragment.create_stacking_context(
|
let mut stacking_context = self.fragment.create_stacking_context(
|
||||||
|
@ -1760,7 +1760,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
&self.base,
|
&self.base,
|
||||||
scroll_policy,
|
scroll_policy,
|
||||||
StackingContextCreationMode::Normal);
|
StackingContextCreationMode::Normal);
|
||||||
stacking_context.children = child_contexts;
|
stacking_context.set_children(child_contexts);
|
||||||
stacking_context
|
stacking_context
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -84,8 +84,10 @@ pub fn build_display_list_for_subtree(root: &mut FlowRef,
|
||||||
let flow_root = flow_ref::deref_mut(root);
|
let flow_root = flow_ref::deref_mut(root);
|
||||||
let layout_context = LayoutContext::new(shared_layout_context);
|
let layout_context = LayoutContext::new(shared_layout_context);
|
||||||
flow_root.traverse_preorder(&ComputeAbsolutePositions { layout_context: &layout_context });
|
flow_root.traverse_preorder(&ComputeAbsolutePositions { layout_context: &layout_context });
|
||||||
|
let mut children = vec![];
|
||||||
flow_root.collect_stacking_contexts(root_stacking_context.id,
|
flow_root.collect_stacking_contexts(root_stacking_context.id,
|
||||||
&mut root_stacking_context.children);
|
&mut children);
|
||||||
|
root_stacking_context.add_children(children);
|
||||||
let mut build_display_list = BuildDisplayList {
|
let mut build_display_list = BuildDisplayList {
|
||||||
state: DisplayListBuildState::new(&layout_context,
|
state: DisplayListBuildState::new(&layout_context,
|
||||||
flow::base(&*flow_root).stacking_context_id),
|
flow::base(&*flow_root).stacking_context_id),
|
||||||
|
|
|
@ -260,7 +260,7 @@ impl WebRenderStackingContextConverter for StackingContext {
|
||||||
builder: &mut webrender_traits::DisplayListBuilder,
|
builder: &mut webrender_traits::DisplayListBuilder,
|
||||||
frame_builder: &mut WebRenderFrameBuilder,
|
frame_builder: &mut WebRenderFrameBuilder,
|
||||||
_force_positioned_stacking_level: bool) {
|
_force_positioned_stacking_level: bool) {
|
||||||
for child in self.children.iter() {
|
for child in self.children() {
|
||||||
while let Some(item) = traversal.advance(self) {
|
while let Some(item) = traversal.advance(self) {
|
||||||
item.convert_to_webrender(builder, frame_builder);
|
item.convert_to_webrender(builder, frame_builder);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue