diff options
author | bors-servo <metajack+bors@gmail.com> | 2015-08-17 13:56:53 -0600 |
---|---|---|
committer | bors-servo <metajack+bors@gmail.com> | 2015-08-17 13:56:53 -0600 |
commit | d654841288ad6c7d4f8d7da3c68d04ef7df2c241 (patch) | |
tree | e0b6e3e13b89ae5b936af6a8511d2110be75af6b | |
parent | 72fa45155b93a9763967cf215e3a9e60e3883cd9 (diff) | |
parent | a30379975a50e52dd8ad7b7b0f95447efe231c5a (diff) | |
download | servo-d654841288ad6c7d4f8d7da3c68d04ef7df2c241.tar.gz servo-d654841288ad6c7d4f8d7da3c68d04ef7df2c241.zip |
Auto merge of #7177 - pcwalton:intervening-inline-block, r=mbrubeck
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.)
r? @mbrubeck
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/7177)
<!-- Reviewable:end -->
-rw-r--r-- | components/layout/block.rs | 6 | ||||
-rw-r--r-- | components/layout/construct.rs | 80 | ||||
-rw-r--r-- | components/layout/flow.rs | 72 | ||||
-rw-r--r-- | components/layout/fragment.rs | 16 | ||||
-rw-r--r-- | components/layout/inline.rs | 73 | ||||
-rw-r--r-- | tests/ref/absolute_hypothetical_with_intervening_inline_block_a.html | 23 | ||||
-rw-r--r-- | tests/ref/absolute_hypothetical_with_intervening_inline_block_ref.html | 3 | ||||
-rw-r--r-- | tests/ref/absolute_inline_containing_block_a.html | 39 | ||||
-rw-r--r-- | tests/ref/absolute_inline_containing_block_ref.html | 14 | ||||
-rw-r--r-- | tests/ref/basic.list | 1 |
10 files changed, 235 insertions, 92 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs index fdfec58e776..c73f97a821b 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -708,9 +708,9 @@ impl BlockFlow { /// Return true if this has a replaced fragment. /// - /// Text, Images, Inline Block and - // Canvas (https://html.spec.whatwg.org/multipage/#replaced-elements) - // fragments are considered as replaced fragments + /// Text, Images, Inline Block and Canvas + /// (https://html.spec.whatwg.org/multipage/#replaced-elements) fragments are considered as + /// replaced fragments. fn is_replaced_content(&self) -> bool { match self.fragment.specific { SpecificFragmentInfo::ScannedText(_) | diff --git a/components/layout/construct.rs b/components/layout/construct.rs index a918e35463b..c9934510424 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -17,10 +17,8 @@ use block::BlockFlow; use context::LayoutContext; use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataWrapper}; use floats::FloatKind; -use flow::{Descendants, AbsDescendants}; -use flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils}; -use flow::{IS_ABSOLUTELY_POSITIONED}; -use flow; +use flow::{self, AbsoluteDescendants, Flow, ImmutableFlowUtils, IS_ABSOLUTELY_POSITIONED}; +use flow::{MutableFlowUtils, MutableOwnedFlowUtils}; use flow_ref::FlowRef; use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo}; use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo}; @@ -72,7 +70,7 @@ pub enum ConstructionResult { /// This node contributed a flow at the proper position in the tree. /// Nothing more needs to be done for this node. It has bubbled up fixed /// and absolute descendant flows that have a containing block above it. - Flow(FlowRef, AbsDescendants), + Flow(FlowRef, AbsoluteDescendants), /// This node contributed some object or objects that will be needed to construct a proper flow /// later up the tree, but these objects have not yet found their home. @@ -120,9 +118,6 @@ pub struct InlineFragmentsConstructionResult { /// Any fragments that succeed the {ib} splits. pub fragments: IntermediateInlineFragments, - - /// Any absolute descendants that we're bubbling up. - pub abs_descendants: AbsDescendants, } /// Represents an {ib} split that has not yet found the containing block that it belongs to. This @@ -167,14 +162,14 @@ pub struct IntermediateInlineFragments { pub fragments: LinkedList<Fragment>, /// The list of absolute descendants of those inline fragments. - pub absolute_descendants: AbsDescendants, + pub absolute_descendants: AbsoluteDescendants, } impl IntermediateInlineFragments { fn new() -> IntermediateInlineFragments { IntermediateInlineFragments { fragments: LinkedList::new(), - absolute_descendants: Descendants::new(), + absolute_descendants: AbsoluteDescendants::new(), } } @@ -424,6 +419,7 @@ impl<'a> FlowConstructor<'a> { fragment_accumulator: InlineFragmentsAccumulator, flow: &mut FlowRef, flow_list: &mut Vec<FlowRef>, + absolute_descendants: &mut AbsoluteDescendants, node: &ThreadSafeLayoutNode) { let mut fragments = fragment_accumulator.to_intermediate_inline_fragments(); if fragments.is_empty() { @@ -432,7 +428,8 @@ impl<'a> FlowConstructor<'a> { strip_ignorable_whitespace_from_start(&mut fragments.fragments); strip_ignorable_whitespace_from_end(&mut fragments.fragments); - if fragments.is_empty() { + if fragments.fragments.is_empty() { + absolute_descendants.push_descendants(fragments.absolute_descendants); return } @@ -469,11 +466,18 @@ impl<'a> FlowConstructor<'a> { } // Set up absolute descendants as necessary. - let contains_positioned_fragments = inline_flow_ref.contains_positioned_fragments(); - if contains_positioned_fragments { - // This is the containing block for all the absolute descendants. - inline_flow_ref.set_absolute_descendants(fragments.absolute_descendants); - } + // + // TODO(pcwalton): The inline flow itself may need to become the containing block for + // absolute descendants in order to handle cases like: + // + // <div> + // <span style="position: relative"> + // <span style="position: absolute; ..."></span> + // </span> + // </div> + // + // See the comment above `flow::AbsoluteDescendantInfo` for more information. + absolute_descendants.push_descendants(fragments.absolute_descendants); { let inline_flow = inline_flow_ref.as_inline(); @@ -503,7 +507,7 @@ impl<'a> FlowConstructor<'a> { node: &ThreadSafeLayoutNode, kid: ThreadSafeLayoutNode, inline_fragment_accumulator: &mut InlineFragmentsAccumulator, - abs_descendants: &mut Descendants) { + abs_descendants: &mut AbsoluteDescendants) { match kid.swap_out_construction_result() { ConstructionResult::None => {} ConstructionResult::Flow(mut kid_flow, kid_abs_descendants) => { @@ -512,7 +516,7 @@ impl<'a> FlowConstructor<'a> { if flow.is_table() && kid_flow.is_table_caption() { self.set_flow_construction_result(&kid, ConstructionResult::Flow(kid_flow, - Descendants::new())) + AbsoluteDescendants::new())) } else if flow.need_anonymous_flow(&*kid_flow) { consecutive_siblings.push(kid_flow) } else { @@ -520,11 +524,14 @@ impl<'a> FlowConstructor<'a> { // handle {ib} splits. debug!("flushing {} inline box(es) to flow A", inline_fragment_accumulator.fragments.fragments.len()); - self.flush_inline_fragments_to_flow_or_list( + let old_inline_fragment_accumulator = mem::replace(inline_fragment_accumulator, - InlineFragmentsAccumulator::new()), + InlineFragmentsAccumulator::new()); + self.flush_inline_fragments_to_flow_or_list( + old_inline_fragment_accumulator, flow, consecutive_siblings, + abs_descendants, node); if !consecutive_siblings.is_empty() { let consecutive_siblings = mem::replace(consecutive_siblings, vec!()); @@ -539,7 +546,6 @@ impl<'a> FlowConstructor<'a> { InlineFragmentsConstructionResult { splits, fragments: successor_fragments, - abs_descendants: kid_abs_descendants, })) => { // Add any {ib} splits. for split in splits.into_iter() { @@ -554,11 +560,14 @@ impl<'a> FlowConstructor<'a> { // Flush any inline fragments that we were gathering up. debug!("flushing {} inline box(es) to flow A", inline_fragment_accumulator.fragments.fragments.len()); + let old_inline_fragment_accumulator = + mem::replace(inline_fragment_accumulator, + InlineFragmentsAccumulator::new()); self.flush_inline_fragments_to_flow_or_list( - mem::replace(inline_fragment_accumulator, - InlineFragmentsAccumulator::new()), + old_inline_fragment_accumulator, flow, consecutive_siblings, + &mut inline_fragment_accumulator.fragments.absolute_descendants, node); // Push the flow generated by the {ib} split onto our list of @@ -572,7 +581,6 @@ impl<'a> FlowConstructor<'a> { // Add the fragments to the list we're maintaining. inline_fragment_accumulator.push_all(successor_fragments); - abs_descendants.push_descendants(kid_abs_descendants); } ConstructionResult::ConstructionItem(ConstructionItem::Whitespace( whitespace_node, @@ -614,7 +622,7 @@ impl<'a> FlowConstructor<'a> { inline_fragment_accumulator.fragments.push_all(initial_fragments); // List of absolute descendants, in tree order. - let mut abs_descendants = Descendants::new(); + let mut abs_descendants = AbsoluteDescendants::new(); for kid in node.children() { if kid.get_pseudo_element_type() != PseudoElementType::Normal { self.process(&kid); @@ -634,6 +642,7 @@ impl<'a> FlowConstructor<'a> { self.flush_inline_fragments_to_flow_or_list(inline_fragment_accumulator, &mut flow, &mut consecutive_siblings, + &mut abs_descendants, node); if !consecutive_siblings.is_empty() { self.generate_anonymous_missing_child(consecutive_siblings, &mut flow, node); @@ -649,7 +658,7 @@ impl<'a> FlowConstructor<'a> { // This is the containing block for all the absolute descendants. flow.set_absolute_descendants(abs_descendants); - abs_descendants = Descendants::new(); + abs_descendants = AbsoluteDescendants::new(); if is_absolutely_positioned { // This is now the only absolute flow in the subtree which hasn't yet // reached its CB. @@ -784,7 +793,7 @@ impl<'a> FlowConstructor<'a> { let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node); fragment_accumulator.bidi_control_chars = bidi_control_chars(&*node.style()); - let mut abs_descendants = Descendants::new(); + let mut abs_descendants = AbsoluteDescendants::new(); // Concatenate all the fragments of our kids, creating {ib} splits as necessary. for kid in node.children() { @@ -830,7 +839,6 @@ impl<'a> FlowConstructor<'a> { InlineFragmentsConstructionResult { splits, fragments: successors, - abs_descendants: kid_abs_descendants, })) => { // Bubble up {ib} splits. @@ -841,7 +849,6 @@ impl<'a> FlowConstructor<'a> { // Push residual fragments. fragment_accumulator.push_all(successors); - abs_descendants.push_descendants(kid_abs_descendants); } ConstructionResult::ConstructionItem(ConstructionItem::Whitespace( whitespace_node, @@ -869,11 +876,11 @@ impl<'a> FlowConstructor<'a> { // Finally, make a new construction result. if opt_inline_block_splits.len() > 0 || !fragment_accumulator.fragments.is_empty() || abs_descendants.len() > 0 { + fragment_accumulator.fragments.absolute_descendants.push_descendants(abs_descendants); let construction_item = ConstructionItem::InlineFragments( InlineFragmentsConstructionResult { splits: opt_inline_block_splits, fragments: fragment_accumulator.to_intermediate_inline_fragments(), - abs_descendants: abs_descendants, }); ConstructionResult::ConstructionItem(construction_item) } else { @@ -924,7 +931,6 @@ impl<'a> FlowConstructor<'a> { ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { splits: LinkedList::new(), fragments: fragments, - abs_descendants: Descendants::new(), }); ConstructionResult::ConstructionItem(construction_item) } @@ -950,12 +956,12 @@ impl<'a> FlowConstructor<'a> { let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node_and_style(node, modified_style); fragment_accumulator.fragments.fragments.push_back(fragment); + fragment_accumulator.fragments.absolute_descendants.push_descendants(abs_descendants); let construction_item = ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { splits: LinkedList::new(), fragments: fragment_accumulator.to_intermediate_inline_fragments(), - abs_descendants: abs_descendants, }); ConstructionResult::ConstructionItem(construction_item) } @@ -976,12 +982,12 @@ impl<'a> FlowConstructor<'a> { let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node); fragment_accumulator.fragments.fragments.push_back(fragment); + fragment_accumulator.fragments.absolute_descendants.push_descendants(abs_descendants); let construction_item = ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { splits: LinkedList::new(), fragments: fragment_accumulator.to_intermediate_inline_fragments(), - abs_descendants: abs_descendants, }); ConstructionResult::ConstructionItem(construction_item) } @@ -1069,8 +1075,8 @@ impl<'a> FlowConstructor<'a> { // First populate the table flow with its children. let construction_result = self.build_flow_for_block_like(table_flow, node); - let mut abs_descendants = Descendants::new(); - let mut fixed_descendants = Descendants::new(); + let mut abs_descendants = AbsoluteDescendants::new(); + let mut fixed_descendants = AbsoluteDescendants::new(); // The order of the caption and the table are not necessarily the same order as in the DOM // tree. All caption blocks are placed before or after the table flow, depending on the @@ -1102,7 +1108,7 @@ impl<'a> FlowConstructor<'a> { // This is the containing block for all the absolute descendants. wrapper_flow.set_absolute_descendants(abs_descendants); - abs_descendants = Descendants::new(); + abs_descendants = AbsoluteDescendants::new(); if is_fixed_positioned { // Send itself along with the other fixed descendants. @@ -1267,7 +1273,7 @@ impl<'a> FlowConstructor<'a> { let mut flow = FlowRef::new(flow as Box<Flow>); flow.finish(); - ConstructionResult::Flow(flow, Descendants::new()) + ConstructionResult::Flow(flow, AbsoluteDescendants::new()) } /// Attempts to perform incremental repair to account for recent changes to this node. This diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 445a3e5a49c..6b11bee1f8c 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -499,7 +499,7 @@ pub trait MutableOwnedFlowUtils { /// Set absolute descendants for this flow. /// /// Set this flow as the Containing Block for all the absolute descendants. - fn set_absolute_descendants(&mut self, abs_descendants: AbsDescendants); + fn set_absolute_descendants(&mut self, abs_descendants: AbsoluteDescendants); } #[derive(RustcEncodable, PartialEq, Debug)] @@ -694,19 +694,17 @@ impl FlowFlags { } } -/// The Descendants of a flow. -/// -/// Also, details about their position wrt this flow. +/// Absolutely-positioned descendants of this flow. #[derive(Clone)] -pub struct Descendants { +pub struct AbsoluteDescendants { /// Links to every descendant. This must be private because it is unsafe to leak `FlowRef`s to /// layout. - descendant_links: Vec<FlowRef>, + descendant_links: Vec<AbsoluteDescendantInfo>, } -impl Descendants { - pub fn new() -> Descendants { - Descendants { +impl AbsoluteDescendants { + pub fn new() -> AbsoluteDescendants { + AbsoluteDescendants { descendant_links: Vec::new(), } } @@ -720,40 +718,63 @@ impl Descendants { } pub fn push(&mut self, given_descendant: FlowRef) { - self.descendant_links.push(given_descendant); + self.descendant_links.push(AbsoluteDescendantInfo { + flow: given_descendant, + }); } /// Push the given descendants on to the existing descendants. /// /// Ignore any static y offsets, because they are None before layout. - pub fn push_descendants(&mut self, given_descendants: Descendants) { + pub fn push_descendants(&mut self, given_descendants: AbsoluteDescendants) { for elem in given_descendants.descendant_links.into_iter() { self.descendant_links.push(elem); } } /// Return an iterator over the descendant flows. - pub fn iter<'a>(&'a mut self) -> DescendantIter<'a> { - DescendantIter { + pub fn iter<'a>(&'a mut self) -> AbsoluteDescendantIter<'a> { + AbsoluteDescendantIter { iter: self.descendant_links.iter_mut(), } } } -pub type AbsDescendants = Descendants; +/// TODO(pcwalton): This structure is going to need a flag to record whether the absolute +/// descendants have reached their containing block yet. The reason is so that we can handle cases +/// like the following: +/// +/// <div> +/// <span id=a style="position: absolute; ...">foo</span> +/// <span style="position: relative"> +/// <span id=b style="position: absolute; ...">bar</span> +/// </span> +/// </div> +/// +/// When we go to create the `InlineFlow` for the outer `div`, our absolute descendants will +/// be `a` and `b`. At this point, we need a way to distinguish between the two, because the +/// containing block for `a` will be different from the containing block for `b`. Specifically, +/// the latter's containing block is the inline flow itself, while the former's containing +/// block is going to be some parent of the outer `div`. Hence we need this flag as a way to +/// distinguish the two; it will be false for `a` and true for `b`. +#[derive(Clone)] +pub struct AbsoluteDescendantInfo { + /// The absolute descendant flow in question. + flow: FlowRef, +} -pub struct DescendantIter<'a> { - iter: IterMut<'a, FlowRef>, +pub struct AbsoluteDescendantIter<'a> { + iter: IterMut<'a, AbsoluteDescendantInfo>, } -impl<'a> Iterator for DescendantIter<'a> { +impl<'a> Iterator for AbsoluteDescendantIter<'a> { type Item = &'a mut (Flow + 'a); fn next(&mut self) -> Option<&'a mut (Flow + 'a)> { - self.iter.next().map(|flow| &mut **flow) + self.iter.next().map(|info| &mut *info.flow) } } -pub type DescendantOffsetIter<'a> = Zip<DescendantIter<'a>, IterMut<'a, Au>>; +pub type AbsoluteDescendantOffsetIter<'a> = Zip<AbsoluteDescendantIter<'a>, IterMut<'a, Au>>; /// Information needed to compute absolute (i.e. viewport-relative) flow positions (not to be /// confused with absolutely-positioned flows). @@ -837,7 +858,7 @@ pub struct BaseFlow { /// Details about descendants with position 'absolute' or 'fixed' for which we are the /// containing block. This is in tree order. This includes any direct children. - pub abs_descendants: AbsDescendants, + pub abs_descendants: AbsoluteDescendants, /// The inline-size of the block container of this flow. Used for computing percentage and /// automatic values for `width`. @@ -1034,7 +1055,7 @@ impl BaseFlow { floats: Floats::new(writing_mode), collapsible_margins: CollapsibleMargins::new(), stacking_relative_position: Point2D::zero(), - abs_descendants: Descendants::new(), + abs_descendants: AbsoluteDescendants::new(), block_container_inline_size: Au(0), block_container_writing_mode: writing_mode, block_container_explicit_block_size: None, @@ -1367,7 +1388,7 @@ impl MutableOwnedFlowUtils for FlowRef { /// This is called during flow construction, so nothing else can be accessing the descendant /// flows. This is enforced by the fact that we have a mutable `FlowRef`, which only flow /// construction is allowed to possess. - fn set_absolute_descendants(&mut self, abs_descendants: AbsDescendants) { + fn set_absolute_descendants(&mut self, abs_descendants: AbsoluteDescendants) { let this = self.clone(); let base = mut_base(&mut **self); base.abs_descendants = abs_descendants; @@ -1414,7 +1435,10 @@ impl ContainingBlockLink { panic!("Link to containing block not established; perhaps you forgot to call \ `set_absolute_descendants`?") } - Some(ref link) => link.upgrade().unwrap().generated_containing_block_size(for_flow), + Some(ref link) => { + let flow = link.upgrade().unwrap(); + flow.generated_containing_block_size(for_flow) + } } } @@ -1429,6 +1453,8 @@ impl ContainingBlockLink { let flow = link.upgrade().unwrap(); if flow.is_block_like() { flow.as_immutable_block().explicit_block_containing_size(layout_context) + } else if flow.is_inline_flow() { + Some(flow.as_immutable_inline().minimum_block_size_above_baseline) } else { None } diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 880e3b4ae4e..60b340195d7 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -2234,6 +2234,22 @@ impl Fragment { pub fn margin_box_inline_size(&self) -> Au { self.border_box.size.inline + self.margin.inline_start_end() } + + /// Returns true if this node *or any of the nodes within its inline fragment context* have + /// non-`static` `position`. + pub fn is_positioned(&self) -> bool { + if self.style.get_box().position != position::T::static_ { + return true + } + if let Some(ref inline_context) = self.inline_context { + for node in inline_context.nodes.iter() { + if node.style.get_box().position != position::T::static_ { + return true + } + } + } + false + } } impl fmt::Debug for Fragment { diff --git a/components/layout/inline.rs b/components/layout/inline.rs index fe1b19001af..39a000d742e 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -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; diff --git a/tests/ref/absolute_hypothetical_with_intervening_inline_block_a.html b/tests/ref/absolute_hypothetical_with_intervening_inline_block_a.html new file mode 100644 index 00000000000..587dde3c589 --- /dev/null +++ b/tests/ref/absolute_hypothetical_with_intervening_inline_block_a.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<style> +em { + position: relative; +} +main { + display: inline-block; +} +section { + display: inline; + position: absolute; + top: 0; + left: 0; + background: white; + width: 48px; + height: 48px; +} +strong { + color: red; +} +</style> +There should be no red.<em><main><section></section></main></em><strong>_</strong> + diff --git a/tests/ref/absolute_hypothetical_with_intervening_inline_block_ref.html b/tests/ref/absolute_hypothetical_with_intervening_inline_block_ref.html new file mode 100644 index 00000000000..985e941cdd9 --- /dev/null +++ b/tests/ref/absolute_hypothetical_with_intervening_inline_block_ref.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +There should be no red. + diff --git a/tests/ref/absolute_inline_containing_block_a.html b/tests/ref/absolute_inline_containing_block_a.html index 84584219490..a10d4fa9e3d 100644 --- a/tests/ref/absolute_inline_containing_block_a.html +++ b/tests/ref/absolute_inline_containing_block_a.html @@ -5,7 +5,6 @@ html, body { margin: 0; font-size: 0.1px; - line-height: 0; } #a { padding-left: 100px; @@ -21,10 +20,46 @@ html, body { height: 100px; background: purple; } +.cover-up-platform-specific-differences { + position: absolute; + background: white; +} +#cover-up-platform-specific-differences-a, #cover-up-platform-specific-differences-b { + left: 0; + width: 300px; +} +#cover-up-platform-specific-differences-c, #cover-up-platform-specific-differences-d { + top: 0; + height: 300px; +} +#cover-up-platform-specific-differences-a { + top: 0; + height: 25px; +} +#cover-up-platform-specific-differences-b { + top: 75px; + height: 100px; +} +#cover-up-platform-specific-differences-c { + left: 0; + width: 125px; +} +#cover-up-platform-specific-differences-d { + left: 175px; + width: 100px; +} </style> </head> <body> -<div><span id=a> </span><span id=b> <div id=c></div></span></span></div> +<div><span id=a>a</span><span id=b><div id=c></div></span></span></div> +<div class=cover-up-platform-specific-differences id=cover-up-platform-specific-differences-a> +</div> +<div class=cover-up-platform-specific-differences id=cover-up-platform-specific-differences-b> +</div> +<div class=cover-up-platform-specific-differences id=cover-up-platform-specific-differences-c> +</div> +<div class=cover-up-platform-specific-differences id=cover-up-platform-specific-differences-d> +</div> </body> </html> diff --git a/tests/ref/absolute_inline_containing_block_ref.html b/tests/ref/absolute_inline_containing_block_ref.html index a7b1de7e4b4..9a36136b853 100644 --- a/tests/ref/absolute_inline_containing_block_ref.html +++ b/tests/ref/absolute_inline_containing_block_ref.html @@ -4,20 +4,20 @@ <style> html, body { margin: 0; - font-size: 0.1px; + font-size: 0; } -#a { +div { position: absolute; - left: 100px; - top: 0; - width: 100px; - height: 100px; + top: 25px; + left: 125px; + width: 50px; + height: 50px; background: purple; } </style> </head> <body> -<div id=a></div> +<div></div> </body> </html> diff --git a/tests/ref/basic.list b/tests/ref/basic.list index 3f6c6c6316f..465e1ea4501 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -10,6 +10,7 @@ fragment=top != ../html/acid2.html acid2_ref.html == abs_rel_explicit_height.html abs_rel_explicit_height_ref.html +== absolute_hypothetical_with_intervening_inline_block_a.html absolute_hypothetical_with_intervening_inline_block_ref.html == absolute_inline_containing_block_a.html absolute_inline_containing_block_ref.html == absolute_z_index_auto_paint_order_a.html absolute_z_index_auto_paint_order_ref.html == acid1_a.html acid1_b.html |