mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
layout: Improve our handling of inline absolute containing blocks.
Several issues are addressed in this commit: * Inline flows now bubble up their absolute descendants instead of making the inline flow the containing block for them. (In the future, we will need to make the inline flow *sometimes* be the containing block for them, but for now it improves sites to unconditionally bubble up.) * Fragments now look at their inline fragment context to determine whether they are positioned. * Inline flows now push the stacking-relative position of the absolute containing block down to their inline-block fragments. * Inline absolute hypothetical fragments can be containing blocks. * Fixes the logic in `containing_block_range_for_flow_surrounding_fragment_at_index`. The condition to determine whether fragments are positioned was inverted! * `Descendants`/`AbsDescendants` has been refactored in order to become more friendly to inline absolute containing blocks in the future. Improves the inline position of the green drop-down arrow in the Google SERPs. (The block position is still wrong.)
This commit is contained in:
parent
55e755e35a
commit
a30379975a
10 changed files with 236 additions and 93 deletions
|
@ -1262,19 +1262,13 @@ impl InlineFlow {
|
|||
while start_index > FragmentIndex(0) &&
|
||||
self.fragments
|
||||
.fragments[(start_index - FragmentIndex(1)).get() as usize]
|
||||
.style
|
||||
.get_box()
|
||||
.position == position::T::static_ {
|
||||
.is_positioned() {
|
||||
start_index = start_index - FragmentIndex(1)
|
||||
}
|
||||
|
||||
let mut end_index = fragment_index + FragmentIndex(1);
|
||||
while end_index < FragmentIndex(self.fragments.fragments.len() as isize) &&
|
||||
self.fragments
|
||||
.fragments[end_index.get() as usize]
|
||||
.style
|
||||
.get_box()
|
||||
.position == position::T::static_ {
|
||||
self.fragments.fragments[end_index.get() as usize].is_positioned() {
|
||||
end_index = end_index + FragmentIndex(1)
|
||||
}
|
||||
|
||||
|
@ -1287,6 +1281,10 @@ impl InlineFlow {
|
|||
SpecificFragmentInfo::InlineAbsolute(ref inline_absolute) => {
|
||||
OpaqueFlow::from_flow(&*inline_absolute.flow_ref) == opaque_flow
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(
|
||||
ref inline_absolute_hypothetical) => {
|
||||
OpaqueFlow::from_flow(&*inline_absolute_hypothetical.flow_ref) == opaque_flow
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}).expect("containing_block_range_for_flow(): couldn't find inline absolute fragment!")
|
||||
|
@ -1600,20 +1598,43 @@ impl Flow for InlineFlow {
|
|||
|
||||
fn compute_absolute_position(&mut self, _: &LayoutContext) {
|
||||
// First, gather up the positions of all the containing blocks (if any).
|
||||
//
|
||||
// FIXME(pcwalton): This will get the absolute containing blocks inside `...` wrong in the
|
||||
// case of something like:
|
||||
//
|
||||
// <span style="position: relative">
|
||||
// Foo
|
||||
// <span style="display: inline-block">...</span>
|
||||
// </span>
|
||||
let mut containing_block_positions = Vec::new();
|
||||
let container_size = Size2D::new(self.base.block_container_inline_size, Au(0));
|
||||
for (fragment_index, fragment) in self.fragments.fragments.iter().enumerate() {
|
||||
if let SpecificFragmentInfo::InlineAbsolute(_) = fragment.specific {
|
||||
let containing_block_range =
|
||||
self.containing_block_range_for_flow_surrounding_fragment_at_index(
|
||||
FragmentIndex(fragment_index as isize));
|
||||
let first_fragment_index = containing_block_range.begin().get() as usize;
|
||||
debug_assert!(first_fragment_index < self.fragments.fragments.len());
|
||||
let first_fragment = &self.fragments.fragments[first_fragment_index];
|
||||
let padding_box_origin = (first_fragment.border_box -
|
||||
first_fragment.style.logical_border_width()).start;
|
||||
containing_block_positions.push(
|
||||
padding_box_origin.to_physical(self.base.writing_mode, container_size));
|
||||
match fragment.specific {
|
||||
SpecificFragmentInfo::InlineAbsolute(_) => {
|
||||
let containing_block_range =
|
||||
self.containing_block_range_for_flow_surrounding_fragment_at_index(
|
||||
FragmentIndex(fragment_index as isize));
|
||||
let first_fragment_index = containing_block_range.begin().get() as usize;
|
||||
debug_assert!(first_fragment_index < self.fragments.fragments.len());
|
||||
let first_fragment = &self.fragments.fragments[first_fragment_index];
|
||||
let padding_box_origin = (first_fragment.border_box -
|
||||
first_fragment.style.logical_border_width()).start;
|
||||
containing_block_positions.push(
|
||||
padding_box_origin.to_physical(self.base.writing_mode, container_size));
|
||||
}
|
||||
SpecificFragmentInfo::InlineBlock(_) if fragment.is_positioned() => {
|
||||
let containing_block_range =
|
||||
self.containing_block_range_for_flow_surrounding_fragment_at_index(
|
||||
FragmentIndex(fragment_index as isize));
|
||||
let first_fragment_index = containing_block_range.begin().get() as usize;
|
||||
debug_assert!(first_fragment_index < self.fragments.fragments.len());
|
||||
let first_fragment = &self.fragments.fragments[first_fragment_index];
|
||||
let padding_box_origin = (first_fragment.border_box -
|
||||
first_fragment.style.logical_border_width()).start;
|
||||
containing_block_positions.push(
|
||||
padding_box_origin.to_physical(self.base.writing_mode, container_size));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1632,12 +1653,23 @@ impl Flow for InlineFlow {
|
|||
let clip = fragment.clipping_region_for_children(&self.base.clip,
|
||||
&stacking_relative_border_box,
|
||||
false);
|
||||
let is_positioned = fragment.is_positioned();
|
||||
match fragment.specific {
|
||||
SpecificFragmentInfo::InlineBlock(ref mut info) => {
|
||||
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
||||
|
||||
let block_flow = info.flow_ref.as_block();
|
||||
block_flow.base.absolute_position_info = self.base.absolute_position_info;
|
||||
|
||||
let stacking_relative_position = self.base.stacking_relative_position;
|
||||
if is_positioned {
|
||||
let padding_box_origin = containing_block_positions.next().unwrap();
|
||||
block_flow.base
|
||||
.absolute_position_info
|
||||
.stacking_relative_position_of_absolute_containing_block =
|
||||
stacking_relative_position + *padding_box_origin;
|
||||
}
|
||||
|
||||
block_flow.base.stacking_relative_position =
|
||||
stacking_relative_border_box.origin;
|
||||
block_flow.base.stacking_relative_position_of_display_port =
|
||||
|
@ -1645,13 +1677,14 @@ impl Flow for InlineFlow {
|
|||
}
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) => {
|
||||
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
||||
|
||||
let block_flow = info.flow_ref.as_block();
|
||||
block_flow.base.absolute_position_info = self.base.absolute_position_info;
|
||||
|
||||
block_flow.base.stacking_relative_position =
|
||||
stacking_relative_border_box.origin;
|
||||
block_flow.base.stacking_relative_position_of_display_port =
|
||||
self.base.stacking_relative_position_of_display_port;
|
||||
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsolute(ref mut info) => {
|
||||
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue