mirror of
https://github.com/servo/servo.git
synced 2025-07-24 07:40:27 +01:00
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 -->
This commit is contained in:
commit
d654841288
10 changed files with 236 additions and 93 deletions
|
@ -708,9 +708,9 @@ impl BlockFlow {
|
||||||
|
|
||||||
/// Return true if this has a replaced fragment.
|
/// Return true if this has a replaced fragment.
|
||||||
///
|
///
|
||||||
/// Text, Images, Inline Block and
|
/// Text, Images, Inline Block and Canvas
|
||||||
// Canvas (https://html.spec.whatwg.org/multipage/#replaced-elements)
|
/// (https://html.spec.whatwg.org/multipage/#replaced-elements) fragments are considered as
|
||||||
// fragments are considered as replaced fragments
|
/// replaced fragments.
|
||||||
fn is_replaced_content(&self) -> bool {
|
fn is_replaced_content(&self) -> bool {
|
||||||
match self.fragment.specific {
|
match self.fragment.specific {
|
||||||
SpecificFragmentInfo::ScannedText(_) |
|
SpecificFragmentInfo::ScannedText(_) |
|
||||||
|
|
|
@ -17,10 +17,8 @@ use block::BlockFlow;
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataWrapper};
|
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataWrapper};
|
||||||
use floats::FloatKind;
|
use floats::FloatKind;
|
||||||
use flow::{Descendants, AbsDescendants};
|
use flow::{self, AbsoluteDescendants, Flow, ImmutableFlowUtils, IS_ABSOLUTELY_POSITIONED};
|
||||||
use flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
|
use flow::{MutableFlowUtils, MutableOwnedFlowUtils};
|
||||||
use flow::{IS_ABSOLUTELY_POSITIONED};
|
|
||||||
use flow;
|
|
||||||
use flow_ref::FlowRef;
|
use flow_ref::FlowRef;
|
||||||
use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo};
|
use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo};
|
||||||
use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo};
|
use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo};
|
||||||
|
@ -72,7 +70,7 @@ pub enum ConstructionResult {
|
||||||
/// This node contributed a flow at the proper position in the tree.
|
/// 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
|
/// 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.
|
/// 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
|
/// 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.
|
/// 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.
|
/// Any fragments that succeed the {ib} splits.
|
||||||
pub fragments: IntermediateInlineFragments,
|
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
|
/// 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>,
|
pub fragments: LinkedList<Fragment>,
|
||||||
|
|
||||||
/// The list of absolute descendants of those inline fragments.
|
/// The list of absolute descendants of those inline fragments.
|
||||||
pub absolute_descendants: AbsDescendants,
|
pub absolute_descendants: AbsoluteDescendants,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntermediateInlineFragments {
|
impl IntermediateInlineFragments {
|
||||||
fn new() -> IntermediateInlineFragments {
|
fn new() -> IntermediateInlineFragments {
|
||||||
IntermediateInlineFragments {
|
IntermediateInlineFragments {
|
||||||
fragments: LinkedList::new(),
|
fragments: LinkedList::new(),
|
||||||
absolute_descendants: Descendants::new(),
|
absolute_descendants: AbsoluteDescendants::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,6 +419,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
fragment_accumulator: InlineFragmentsAccumulator,
|
fragment_accumulator: InlineFragmentsAccumulator,
|
||||||
flow: &mut FlowRef,
|
flow: &mut FlowRef,
|
||||||
flow_list: &mut Vec<FlowRef>,
|
flow_list: &mut Vec<FlowRef>,
|
||||||
|
absolute_descendants: &mut AbsoluteDescendants,
|
||||||
node: &ThreadSafeLayoutNode) {
|
node: &ThreadSafeLayoutNode) {
|
||||||
let mut fragments = fragment_accumulator.to_intermediate_inline_fragments();
|
let mut fragments = fragment_accumulator.to_intermediate_inline_fragments();
|
||||||
if fragments.is_empty() {
|
if fragments.is_empty() {
|
||||||
|
@ -432,7 +428,8 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
strip_ignorable_whitespace_from_start(&mut fragments.fragments);
|
strip_ignorable_whitespace_from_start(&mut fragments.fragments);
|
||||||
strip_ignorable_whitespace_from_end(&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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,11 +466,18 @@ impl<'a> FlowConstructor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up absolute descendants as necessary.
|
// Set up absolute descendants as necessary.
|
||||||
let contains_positioned_fragments = inline_flow_ref.contains_positioned_fragments();
|
//
|
||||||
if contains_positioned_fragments {
|
// TODO(pcwalton): The inline flow itself may need to become the containing block for
|
||||||
// This is the containing block for all the absolute descendants.
|
// absolute descendants in order to handle cases like:
|
||||||
inline_flow_ref.set_absolute_descendants(fragments.absolute_descendants);
|
//
|
||||||
}
|
// <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();
|
let inline_flow = inline_flow_ref.as_inline();
|
||||||
|
@ -503,7 +507,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
node: &ThreadSafeLayoutNode,
|
node: &ThreadSafeLayoutNode,
|
||||||
kid: ThreadSafeLayoutNode,
|
kid: ThreadSafeLayoutNode,
|
||||||
inline_fragment_accumulator: &mut InlineFragmentsAccumulator,
|
inline_fragment_accumulator: &mut InlineFragmentsAccumulator,
|
||||||
abs_descendants: &mut Descendants) {
|
abs_descendants: &mut AbsoluteDescendants) {
|
||||||
match kid.swap_out_construction_result() {
|
match kid.swap_out_construction_result() {
|
||||||
ConstructionResult::None => {}
|
ConstructionResult::None => {}
|
||||||
ConstructionResult::Flow(mut kid_flow, kid_abs_descendants) => {
|
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() {
|
if flow.is_table() && kid_flow.is_table_caption() {
|
||||||
self.set_flow_construction_result(&kid,
|
self.set_flow_construction_result(&kid,
|
||||||
ConstructionResult::Flow(kid_flow,
|
ConstructionResult::Flow(kid_flow,
|
||||||
Descendants::new()))
|
AbsoluteDescendants::new()))
|
||||||
} else if flow.need_anonymous_flow(&*kid_flow) {
|
} else if flow.need_anonymous_flow(&*kid_flow) {
|
||||||
consecutive_siblings.push(kid_flow)
|
consecutive_siblings.push(kid_flow)
|
||||||
} else {
|
} else {
|
||||||
|
@ -520,11 +524,14 @@ impl<'a> FlowConstructor<'a> {
|
||||||
// handle {ib} splits.
|
// handle {ib} splits.
|
||||||
debug!("flushing {} inline box(es) to flow A",
|
debug!("flushing {} inline box(es) to flow A",
|
||||||
inline_fragment_accumulator.fragments.fragments.len());
|
inline_fragment_accumulator.fragments.fragments.len());
|
||||||
self.flush_inline_fragments_to_flow_or_list(
|
let old_inline_fragment_accumulator =
|
||||||
mem::replace(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,
|
flow,
|
||||||
consecutive_siblings,
|
consecutive_siblings,
|
||||||
|
abs_descendants,
|
||||||
node);
|
node);
|
||||||
if !consecutive_siblings.is_empty() {
|
if !consecutive_siblings.is_empty() {
|
||||||
let consecutive_siblings = mem::replace(consecutive_siblings, vec!());
|
let consecutive_siblings = mem::replace(consecutive_siblings, vec!());
|
||||||
|
@ -539,7 +546,6 @@ impl<'a> FlowConstructor<'a> {
|
||||||
InlineFragmentsConstructionResult {
|
InlineFragmentsConstructionResult {
|
||||||
splits,
|
splits,
|
||||||
fragments: successor_fragments,
|
fragments: successor_fragments,
|
||||||
abs_descendants: kid_abs_descendants,
|
|
||||||
})) => {
|
})) => {
|
||||||
// Add any {ib} splits.
|
// Add any {ib} splits.
|
||||||
for split in splits.into_iter() {
|
for split in splits.into_iter() {
|
||||||
|
@ -554,11 +560,14 @@ impl<'a> FlowConstructor<'a> {
|
||||||
// Flush any inline fragments that we were gathering up.
|
// Flush any inline fragments that we were gathering up.
|
||||||
debug!("flushing {} inline box(es) to flow A",
|
debug!("flushing {} inline box(es) to flow A",
|
||||||
inline_fragment_accumulator.fragments.fragments.len());
|
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(
|
self.flush_inline_fragments_to_flow_or_list(
|
||||||
mem::replace(inline_fragment_accumulator,
|
old_inline_fragment_accumulator,
|
||||||
InlineFragmentsAccumulator::new()),
|
|
||||||
flow,
|
flow,
|
||||||
consecutive_siblings,
|
consecutive_siblings,
|
||||||
|
&mut inline_fragment_accumulator.fragments.absolute_descendants,
|
||||||
node);
|
node);
|
||||||
|
|
||||||
// Push the flow generated by the {ib} split onto our list of
|
// 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.
|
// Add the fragments to the list we're maintaining.
|
||||||
inline_fragment_accumulator.push_all(successor_fragments);
|
inline_fragment_accumulator.push_all(successor_fragments);
|
||||||
abs_descendants.push_descendants(kid_abs_descendants);
|
|
||||||
}
|
}
|
||||||
ConstructionResult::ConstructionItem(ConstructionItem::Whitespace(
|
ConstructionResult::ConstructionItem(ConstructionItem::Whitespace(
|
||||||
whitespace_node,
|
whitespace_node,
|
||||||
|
@ -614,7 +622,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
inline_fragment_accumulator.fragments.push_all(initial_fragments);
|
inline_fragment_accumulator.fragments.push_all(initial_fragments);
|
||||||
|
|
||||||
// List of absolute descendants, in tree order.
|
// List of absolute descendants, in tree order.
|
||||||
let mut abs_descendants = Descendants::new();
|
let mut abs_descendants = AbsoluteDescendants::new();
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
if kid.get_pseudo_element_type() != PseudoElementType::Normal {
|
if kid.get_pseudo_element_type() != PseudoElementType::Normal {
|
||||||
self.process(&kid);
|
self.process(&kid);
|
||||||
|
@ -634,6 +642,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
self.flush_inline_fragments_to_flow_or_list(inline_fragment_accumulator,
|
self.flush_inline_fragments_to_flow_or_list(inline_fragment_accumulator,
|
||||||
&mut flow,
|
&mut flow,
|
||||||
&mut consecutive_siblings,
|
&mut consecutive_siblings,
|
||||||
|
&mut abs_descendants,
|
||||||
node);
|
node);
|
||||||
if !consecutive_siblings.is_empty() {
|
if !consecutive_siblings.is_empty() {
|
||||||
self.generate_anonymous_missing_child(consecutive_siblings, &mut flow, node);
|
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.
|
// This is the containing block for all the absolute descendants.
|
||||||
flow.set_absolute_descendants(abs_descendants);
|
flow.set_absolute_descendants(abs_descendants);
|
||||||
|
|
||||||
abs_descendants = Descendants::new();
|
abs_descendants = AbsoluteDescendants::new();
|
||||||
if is_absolutely_positioned {
|
if is_absolutely_positioned {
|
||||||
// This is now the only absolute flow in the subtree which hasn't yet
|
// This is now the only absolute flow in the subtree which hasn't yet
|
||||||
// reached its CB.
|
// reached its CB.
|
||||||
|
@ -784,7 +793,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
||||||
fragment_accumulator.bidi_control_chars = bidi_control_chars(&*node.style());
|
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.
|
// Concatenate all the fragments of our kids, creating {ib} splits as necessary.
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
|
@ -830,7 +839,6 @@ impl<'a> FlowConstructor<'a> {
|
||||||
InlineFragmentsConstructionResult {
|
InlineFragmentsConstructionResult {
|
||||||
splits,
|
splits,
|
||||||
fragments: successors,
|
fragments: successors,
|
||||||
abs_descendants: kid_abs_descendants,
|
|
||||||
})) => {
|
})) => {
|
||||||
|
|
||||||
// Bubble up {ib} splits.
|
// Bubble up {ib} splits.
|
||||||
|
@ -841,7 +849,6 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
// Push residual fragments.
|
// Push residual fragments.
|
||||||
fragment_accumulator.push_all(successors);
|
fragment_accumulator.push_all(successors);
|
||||||
abs_descendants.push_descendants(kid_abs_descendants);
|
|
||||||
}
|
}
|
||||||
ConstructionResult::ConstructionItem(ConstructionItem::Whitespace(
|
ConstructionResult::ConstructionItem(ConstructionItem::Whitespace(
|
||||||
whitespace_node,
|
whitespace_node,
|
||||||
|
@ -869,11 +876,11 @@ impl<'a> FlowConstructor<'a> {
|
||||||
// Finally, make a new construction result.
|
// Finally, make a new construction result.
|
||||||
if opt_inline_block_splits.len() > 0 || !fragment_accumulator.fragments.is_empty()
|
if opt_inline_block_splits.len() > 0 || !fragment_accumulator.fragments.is_empty()
|
||||||
|| abs_descendants.len() > 0 {
|
|| abs_descendants.len() > 0 {
|
||||||
|
fragment_accumulator.fragments.absolute_descendants.push_descendants(abs_descendants);
|
||||||
let construction_item = ConstructionItem::InlineFragments(
|
let construction_item = ConstructionItem::InlineFragments(
|
||||||
InlineFragmentsConstructionResult {
|
InlineFragmentsConstructionResult {
|
||||||
splits: opt_inline_block_splits,
|
splits: opt_inline_block_splits,
|
||||||
fragments: fragment_accumulator.to_intermediate_inline_fragments(),
|
fragments: fragment_accumulator.to_intermediate_inline_fragments(),
|
||||||
abs_descendants: abs_descendants,
|
|
||||||
});
|
});
|
||||||
ConstructionResult::ConstructionItem(construction_item)
|
ConstructionResult::ConstructionItem(construction_item)
|
||||||
} else {
|
} else {
|
||||||
|
@ -924,7 +931,6 @@ impl<'a> FlowConstructor<'a> {
|
||||||
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||||
splits: LinkedList::new(),
|
splits: LinkedList::new(),
|
||||||
fragments: fragments,
|
fragments: fragments,
|
||||||
abs_descendants: Descendants::new(),
|
|
||||||
});
|
});
|
||||||
ConstructionResult::ConstructionItem(construction_item)
|
ConstructionResult::ConstructionItem(construction_item)
|
||||||
}
|
}
|
||||||
|
@ -950,12 +956,12 @@ impl<'a> FlowConstructor<'a> {
|
||||||
let mut fragment_accumulator =
|
let mut fragment_accumulator =
|
||||||
InlineFragmentsAccumulator::from_inline_node_and_style(node, modified_style);
|
InlineFragmentsAccumulator::from_inline_node_and_style(node, modified_style);
|
||||||
fragment_accumulator.fragments.fragments.push_back(fragment);
|
fragment_accumulator.fragments.fragments.push_back(fragment);
|
||||||
|
fragment_accumulator.fragments.absolute_descendants.push_descendants(abs_descendants);
|
||||||
|
|
||||||
let construction_item =
|
let construction_item =
|
||||||
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||||
splits: LinkedList::new(),
|
splits: LinkedList::new(),
|
||||||
fragments: fragment_accumulator.to_intermediate_inline_fragments(),
|
fragments: fragment_accumulator.to_intermediate_inline_fragments(),
|
||||||
abs_descendants: abs_descendants,
|
|
||||||
});
|
});
|
||||||
ConstructionResult::ConstructionItem(construction_item)
|
ConstructionResult::ConstructionItem(construction_item)
|
||||||
}
|
}
|
||||||
|
@ -976,12 +982,12 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|
|
||||||
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
||||||
fragment_accumulator.fragments.fragments.push_back(fragment);
|
fragment_accumulator.fragments.fragments.push_back(fragment);
|
||||||
|
fragment_accumulator.fragments.absolute_descendants.push_descendants(abs_descendants);
|
||||||
|
|
||||||
let construction_item =
|
let construction_item =
|
||||||
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||||
splits: LinkedList::new(),
|
splits: LinkedList::new(),
|
||||||
fragments: fragment_accumulator.to_intermediate_inline_fragments(),
|
fragments: fragment_accumulator.to_intermediate_inline_fragments(),
|
||||||
abs_descendants: abs_descendants,
|
|
||||||
});
|
});
|
||||||
ConstructionResult::ConstructionItem(construction_item)
|
ConstructionResult::ConstructionItem(construction_item)
|
||||||
}
|
}
|
||||||
|
@ -1069,8 +1075,8 @@ impl<'a> FlowConstructor<'a> {
|
||||||
// First populate the table flow with its children.
|
// First populate the table flow with its children.
|
||||||
let construction_result = self.build_flow_for_block_like(table_flow, node);
|
let construction_result = self.build_flow_for_block_like(table_flow, node);
|
||||||
|
|
||||||
let mut abs_descendants = Descendants::new();
|
let mut abs_descendants = AbsoluteDescendants::new();
|
||||||
let mut fixed_descendants = Descendants::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
|
// 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
|
// 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.
|
// This is the containing block for all the absolute descendants.
|
||||||
wrapper_flow.set_absolute_descendants(abs_descendants);
|
wrapper_flow.set_absolute_descendants(abs_descendants);
|
||||||
|
|
||||||
abs_descendants = Descendants::new();
|
abs_descendants = AbsoluteDescendants::new();
|
||||||
|
|
||||||
if is_fixed_positioned {
|
if is_fixed_positioned {
|
||||||
// Send itself along with the other fixed descendants.
|
// 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>);
|
let mut flow = FlowRef::new(flow as Box<Flow>);
|
||||||
flow.finish();
|
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
|
/// Attempts to perform incremental repair to account for recent changes to this node. This
|
||||||
|
|
|
@ -499,7 +499,7 @@ pub trait MutableOwnedFlowUtils {
|
||||||
/// Set absolute descendants for this flow.
|
/// Set absolute descendants for this flow.
|
||||||
///
|
///
|
||||||
/// Set this flow as the Containing Block for all the absolute descendants.
|
/// 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)]
|
#[derive(RustcEncodable, PartialEq, Debug)]
|
||||||
|
@ -694,19 +694,17 @@ impl FlowFlags {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Descendants of a flow.
|
/// Absolutely-positioned descendants of this flow.
|
||||||
///
|
|
||||||
/// Also, details about their position wrt this flow.
|
|
||||||
#[derive(Clone)]
|
#[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
|
/// Links to every descendant. This must be private because it is unsafe to leak `FlowRef`s to
|
||||||
/// layout.
|
/// layout.
|
||||||
descendant_links: Vec<FlowRef>,
|
descendant_links: Vec<AbsoluteDescendantInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Descendants {
|
impl AbsoluteDescendants {
|
||||||
pub fn new() -> Descendants {
|
pub fn new() -> AbsoluteDescendants {
|
||||||
Descendants {
|
AbsoluteDescendants {
|
||||||
descendant_links: Vec::new(),
|
descendant_links: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -720,40 +718,63 @@ impl Descendants {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, given_descendant: FlowRef) {
|
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.
|
/// Push the given descendants on to the existing descendants.
|
||||||
///
|
///
|
||||||
/// Ignore any static y offsets, because they are None before layout.
|
/// 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() {
|
for elem in given_descendants.descendant_links.into_iter() {
|
||||||
self.descendant_links.push(elem);
|
self.descendant_links.push(elem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an iterator over the descendant flows.
|
/// Return an iterator over the descendant flows.
|
||||||
pub fn iter<'a>(&'a mut self) -> DescendantIter<'a> {
|
pub fn iter<'a>(&'a mut self) -> AbsoluteDescendantIter<'a> {
|
||||||
DescendantIter {
|
AbsoluteDescendantIter {
|
||||||
iter: self.descendant_links.iter_mut(),
|
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
|
||||||
pub struct DescendantIter<'a> {
|
/// like the following:
|
||||||
iter: IterMut<'a, FlowRef>,
|
///
|
||||||
|
/// <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,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for DescendantIter<'a> {
|
pub struct AbsoluteDescendantIter<'a> {
|
||||||
|
iter: IterMut<'a, AbsoluteDescendantInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for AbsoluteDescendantIter<'a> {
|
||||||
type Item = &'a mut (Flow + 'a);
|
type Item = &'a mut (Flow + 'a);
|
||||||
fn next(&mut self) -> Option<&'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
|
/// Information needed to compute absolute (i.e. viewport-relative) flow positions (not to be
|
||||||
/// confused with absolutely-positioned flows).
|
/// 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
|
/// 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.
|
/// 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
|
/// The inline-size of the block container of this flow. Used for computing percentage and
|
||||||
/// automatic values for `width`.
|
/// automatic values for `width`.
|
||||||
|
@ -1034,7 +1055,7 @@ impl BaseFlow {
|
||||||
floats: Floats::new(writing_mode),
|
floats: Floats::new(writing_mode),
|
||||||
collapsible_margins: CollapsibleMargins::new(),
|
collapsible_margins: CollapsibleMargins::new(),
|
||||||
stacking_relative_position: Point2D::zero(),
|
stacking_relative_position: Point2D::zero(),
|
||||||
abs_descendants: Descendants::new(),
|
abs_descendants: AbsoluteDescendants::new(),
|
||||||
block_container_inline_size: Au(0),
|
block_container_inline_size: Au(0),
|
||||||
block_container_writing_mode: writing_mode,
|
block_container_writing_mode: writing_mode,
|
||||||
block_container_explicit_block_size: None,
|
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
|
/// 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
|
/// flows. This is enforced by the fact that we have a mutable `FlowRef`, which only flow
|
||||||
/// construction is allowed to possess.
|
/// 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 this = self.clone();
|
||||||
let base = mut_base(&mut **self);
|
let base = mut_base(&mut **self);
|
||||||
base.abs_descendants = abs_descendants;
|
base.abs_descendants = abs_descendants;
|
||||||
|
@ -1414,7 +1435,10 @@ impl ContainingBlockLink {
|
||||||
panic!("Link to containing block not established; perhaps you forgot to call \
|
panic!("Link to containing block not established; perhaps you forgot to call \
|
||||||
`set_absolute_descendants`?")
|
`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();
|
let flow = link.upgrade().unwrap();
|
||||||
if flow.is_block_like() {
|
if flow.is_block_like() {
|
||||||
flow.as_immutable_block().explicit_block_containing_size(layout_context)
|
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 {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -2234,6 +2234,22 @@ impl Fragment {
|
||||||
pub fn margin_box_inline_size(&self) -> Au {
|
pub fn margin_box_inline_size(&self) -> Au {
|
||||||
self.border_box.size.inline + self.margin.inline_start_end()
|
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 {
|
impl fmt::Debug for Fragment {
|
||||||
|
|
|
@ -1262,19 +1262,13 @@ impl InlineFlow {
|
||||||
while start_index > FragmentIndex(0) &&
|
while start_index > FragmentIndex(0) &&
|
||||||
self.fragments
|
self.fragments
|
||||||
.fragments[(start_index - FragmentIndex(1)).get() as usize]
|
.fragments[(start_index - FragmentIndex(1)).get() as usize]
|
||||||
.style
|
.is_positioned() {
|
||||||
.get_box()
|
|
||||||
.position == position::T::static_ {
|
|
||||||
start_index = start_index - FragmentIndex(1)
|
start_index = start_index - FragmentIndex(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut end_index = fragment_index + FragmentIndex(1);
|
let mut end_index = fragment_index + FragmentIndex(1);
|
||||||
while end_index < FragmentIndex(self.fragments.fragments.len() as isize) &&
|
while end_index < FragmentIndex(self.fragments.fragments.len() as isize) &&
|
||||||
self.fragments
|
self.fragments.fragments[end_index.get() as usize].is_positioned() {
|
||||||
.fragments[end_index.get() as usize]
|
|
||||||
.style
|
|
||||||
.get_box()
|
|
||||||
.position == position::T::static_ {
|
|
||||||
end_index = end_index + FragmentIndex(1)
|
end_index = end_index + FragmentIndex(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1287,6 +1281,10 @@ impl InlineFlow {
|
||||||
SpecificFragmentInfo::InlineAbsolute(ref inline_absolute) => {
|
SpecificFragmentInfo::InlineAbsolute(ref inline_absolute) => {
|
||||||
OpaqueFlow::from_flow(&*inline_absolute.flow_ref) == opaque_flow
|
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,
|
_ => false,
|
||||||
}
|
}
|
||||||
}).expect("containing_block_range_for_flow(): couldn't find inline absolute fragment!")
|
}).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) {
|
fn compute_absolute_position(&mut self, _: &LayoutContext) {
|
||||||
// First, gather up the positions of all the containing blocks (if any).
|
// 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 mut containing_block_positions = Vec::new();
|
||||||
let container_size = Size2D::new(self.base.block_container_inline_size, Au(0));
|
let container_size = Size2D::new(self.base.block_container_inline_size, Au(0));
|
||||||
for (fragment_index, fragment) in self.fragments.fragments.iter().enumerate() {
|
for (fragment_index, fragment) in self.fragments.fragments.iter().enumerate() {
|
||||||
if let SpecificFragmentInfo::InlineAbsolute(_) = fragment.specific {
|
match fragment.specific {
|
||||||
let containing_block_range =
|
SpecificFragmentInfo::InlineAbsolute(_) => {
|
||||||
self.containing_block_range_for_flow_surrounding_fragment_at_index(
|
let containing_block_range =
|
||||||
FragmentIndex(fragment_index as isize));
|
self.containing_block_range_for_flow_surrounding_fragment_at_index(
|
||||||
let first_fragment_index = containing_block_range.begin().get() as usize;
|
FragmentIndex(fragment_index as isize));
|
||||||
debug_assert!(first_fragment_index < self.fragments.fragments.len());
|
let first_fragment_index = containing_block_range.begin().get() as usize;
|
||||||
let first_fragment = &self.fragments.fragments[first_fragment_index];
|
debug_assert!(first_fragment_index < self.fragments.fragments.len());
|
||||||
let padding_box_origin = (first_fragment.border_box -
|
let first_fragment = &self.fragments.fragments[first_fragment_index];
|
||||||
first_fragment.style.logical_border_width()).start;
|
let padding_box_origin = (first_fragment.border_box -
|
||||||
containing_block_positions.push(
|
first_fragment.style.logical_border_width()).start;
|
||||||
padding_box_origin.to_physical(self.base.writing_mode, container_size));
|
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,
|
let clip = fragment.clipping_region_for_children(&self.base.clip,
|
||||||
&stacking_relative_border_box,
|
&stacking_relative_border_box,
|
||||||
false);
|
false);
|
||||||
|
let is_positioned = fragment.is_positioned();
|
||||||
match fragment.specific {
|
match fragment.specific {
|
||||||
SpecificFragmentInfo::InlineBlock(ref mut info) => {
|
SpecificFragmentInfo::InlineBlock(ref mut info) => {
|
||||||
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
||||||
|
|
||||||
let block_flow = info.flow_ref.as_block();
|
let block_flow = info.flow_ref.as_block();
|
||||||
block_flow.base.absolute_position_info = self.base.absolute_position_info;
|
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 =
|
block_flow.base.stacking_relative_position =
|
||||||
stacking_relative_border_box.origin;
|
stacking_relative_border_box.origin;
|
||||||
block_flow.base.stacking_relative_position_of_display_port =
|
block_flow.base.stacking_relative_position_of_display_port =
|
||||||
|
@ -1645,13 +1677,14 @@ impl Flow for InlineFlow {
|
||||||
}
|
}
|
||||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) => {
|
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) => {
|
||||||
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
||||||
|
|
||||||
let block_flow = info.flow_ref.as_block();
|
let block_flow = info.flow_ref.as_block();
|
||||||
block_flow.base.absolute_position_info = self.base.absolute_position_info;
|
block_flow.base.absolute_position_info = self.base.absolute_position_info;
|
||||||
|
|
||||||
block_flow.base.stacking_relative_position =
|
block_flow.base.stacking_relative_position =
|
||||||
stacking_relative_border_box.origin;
|
stacking_relative_border_box.origin;
|
||||||
block_flow.base.stacking_relative_position_of_display_port =
|
block_flow.base.stacking_relative_position_of_display_port =
|
||||||
self.base.stacking_relative_position_of_display_port;
|
self.base.stacking_relative_position_of_display_port;
|
||||||
|
|
||||||
}
|
}
|
||||||
SpecificFragmentInfo::InlineAbsolute(ref mut info) => {
|
SpecificFragmentInfo::InlineAbsolute(ref mut info) => {
|
||||||
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
There should be no red.
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
html, body {
|
html, body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.1px;
|
font-size: 0.1px;
|
||||||
line-height: 0;
|
|
||||||
}
|
}
|
||||||
#a {
|
#a {
|
||||||
padding-left: 100px;
|
padding-left: 100px;
|
||||||
|
@ -21,10 +20,46 @@ html, body {
|
||||||
height: 100px;
|
height: 100px;
|
||||||
background: purple;
|
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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -4,20 +4,20 @@
|
||||||
<style>
|
<style>
|
||||||
html, body {
|
html, body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.1px;
|
font-size: 0;
|
||||||
}
|
}
|
||||||
#a {
|
div {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 100px;
|
top: 25px;
|
||||||
top: 0;
|
left: 125px;
|
||||||
width: 100px;
|
width: 50px;
|
||||||
height: 100px;
|
height: 50px;
|
||||||
background: purple;
|
background: purple;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id=a></div>
|
<div></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
fragment=top != ../html/acid2.html acid2_ref.html
|
fragment=top != ../html/acid2.html acid2_ref.html
|
||||||
|
|
||||||
== abs_rel_explicit_height.html abs_rel_explicit_height_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_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
|
== absolute_z_index_auto_paint_order_a.html absolute_z_index_auto_paint_order_ref.html
|
||||||
== acid1_a.html acid1_b.html
|
== acid1_a.html acid1_b.html
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue