servo: Merge #18123 - Improve containing block creation for position:absolute flows (from mrobinson:absolute-containing-blocks); r=pcwalton

Instead of only promoting flows with positioned fragments to containing
blocks, also do this for flows which have the transform, perspective or
filter properties set. This is what the spec requires and also fixes
some failing tests. It will allow us to stop creating stacking contexts
for overflow:hidden and overflow:scroll flows.

Fixes #18091.

<!-- 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 #18091  (github issue number if applicable).

<!-- Either: -->
- [x] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- 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: 12607531d812ee87e0b4a70f961c1aa3ec4c414d

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : d7e86671954303af12faf807759c6a27d5570267
This commit is contained in:
Martin Robinson 2017-08-17 19:42:20 -05:00
parent 2a915752c1
commit 1a27a5a33d
10 changed files with 95 additions and 29 deletions

View File

@ -448,20 +448,16 @@ pub struct AbsoluteAssignBSizesTraversal<'a>(pub &'a SharedStyleContext<'a>);
impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> {
#[inline]
fn process(&self, flow: &mut Flow) {
{
// The root of the absolute flow tree is definitely not absolutely
// positioned. Nothing to process here.
let flow: &Flow = flow;
if flow.contains_roots_of_absolute_flow_tree() {
return;
}
if !flow.is_block_like() {
return
}
if !flow.is_block_like() {
return
}
// This flow might not be an absolutely positioned flow if it is the root of the tree.
let block = flow.as_mut_block();
debug_assert!(block.base.flags.contains(IS_ABSOLUTELY_POSITIONED));
if !block.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
return;
}
if !block.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) {
return
}
@ -2106,6 +2102,17 @@ impl Flow for BlockFlow {
(self.fragment.border_box - self.fragment.style().logical_border_width()).size
}
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.contains_relatively_positioned_fragments() || self.is_root() ||
self.fragment.has_filter_transform_or_perspective()
}
/// Returns true if this is an absolute containing block.
fn is_absolute_containing_block(&self) -> bool {
self.contains_positioned_fragments() || self.fragment.has_filter_transform_or_perspective()
}
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) &&
self.fragment.style().logical_position().inline_start ==

View File

@ -981,6 +981,14 @@ impl Flow for FlexFlow {
self.block_flow.compute_overflow()
}
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.block_flow.contains_roots_of_absolute_flow_tree()
}
fn is_absolute_containing_block(&self) -> bool {
self.block_flow.is_absolute_containing_block()
}
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_size(flow)
}

View File

@ -407,6 +407,11 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
self.contains_positioned_fragments()
}
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.contains_relatively_positioned_fragments() || self.is_root()
}
/// Updates the inline position of a child flow during the assign-height traversal. At present,
/// this is only used for absolutely-positioned inline-blocks.
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au);
@ -502,9 +507,6 @@ pub trait ImmutableFlowUtils {
/// Returns true if this flow is one of table-related flows.
fn is_table_kind(self) -> bool;
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
fn contains_roots_of_absolute_flow_tree(&self) -> bool;
/// Returns true if this flow has no children.
fn is_leaf(self) -> bool;
@ -1198,11 +1200,6 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
}
}
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.contains_relatively_positioned_fragments() || self.is_root()
}
/// Returns true if this flow has no children.
fn is_leaf(self) -> bool {
base(self).children.is_empty()

View File

@ -2487,6 +2487,13 @@ impl Fragment {
stacking_relative_border_box.size.height - border_padding.vertical()))
}
/// Returns true if this fragment has a filter, transform, or perspective property set.
pub fn has_filter_transform_or_perspective(&self) -> bool {
self.style().get_box().transform.0.is_some() ||
!self.style().get_effects().filter.0.is_empty() ||
self.style().get_box().perspective != Either::Second(values::None_)
}
/// Returns true if this fragment establishes a new stacking context and false otherwise.
pub fn establishes_stacking_context(&self) -> bool {
// Text fragments shouldn't create stacking contexts.
@ -2500,22 +2507,17 @@ impl Fragment {
if self.style().get_effects().opacity != 1.0 {
return true
}
if !self.style().get_effects().filter.0.is_empty() {
return true
}
if self.style().get_effects().mix_blend_mode != mix_blend_mode::T::normal {
return true
}
if self.style().get_box().transform.0.is_some() ||
self.style().get_box().transform_style == transform_style::T::preserve_3d ||
self.style().overrides_transform_style() {
return true
if self.has_filter_transform_or_perspective() {
return true;
}
// TODO(mrobinson): Determine if this is necessary, since blocks with
// transformations already create stacking contexts.
if let Either::First(ref _length) = self.style().get_box().perspective {
if self.style().get_box().transform_style == transform_style::T::preserve_3d ||
self.style().overrides_transform_style() {
return true
}

View File

@ -127,6 +127,10 @@ impl Flow for ListItemFlow {
self.block_flow.place_float_if_applicable()
}
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.block_flow.contains_roots_of_absolute_flow_tree()
}
fn is_absolute_containing_block(&self) -> bool {
self.block_flow.is_absolute_containing_block()
}

View File

@ -201,6 +201,14 @@ impl Flow for MulticolFlow {
self.block_flow.compute_overflow()
}
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.block_flow.contains_roots_of_absolute_flow_tree()
}
fn is_absolute_containing_block(&self) -> bool {
self.block_flow.is_absolute_containing_block()
}
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_size(flow)
}
@ -283,6 +291,14 @@ impl Flow for MulticolColumnFlow {
self.block_flow.compute_overflow()
}
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.block_flow.contains_roots_of_absolute_flow_tree()
}
fn is_absolute_containing_block(&self) -> bool {
self.block_flow.is_absolute_containing_block()
}
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_size(flow)
}

View File

@ -91,6 +91,14 @@ impl Flow for TableCaptionFlow {
self.block_flow.compute_overflow()
}
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.block_flow.contains_roots_of_absolute_flow_tree()
}
fn is_absolute_containing_block(&self) -> bool {
self.block_flow.is_absolute_containing_block()
}
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_size(flow)
}

View File

@ -271,6 +271,14 @@ impl Flow for TableCellFlow {
self.block_flow.compute_overflow()
}
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.block_flow.contains_roots_of_absolute_flow_tree()
}
fn is_absolute_containing_block(&self) -> bool {
self.block_flow.is_absolute_containing_block()
}
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_size(flow)
}

View File

@ -489,6 +489,14 @@ impl Flow for TableRowFlow {
self.block_flow.compute_overflow()
}
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.block_flow.contains_roots_of_absolute_flow_tree()
}
fn is_absolute_containing_block(&self) -> bool {
self.block_flow.is_absolute_containing_block()
}
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_size(flow)
}

View File

@ -194,6 +194,14 @@ impl Flow for TableRowGroupFlow {
self.block_flow.compute_overflow()
}
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.block_flow.contains_roots_of_absolute_flow_tree()
}
fn is_absolute_containing_block(&self) -> bool {
self.block_flow.is_absolute_containing_block()
}
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_size(flow)
}