mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Auto merge of #14035 - Permutatrix:iss-14030, r=emilio
Don't mark the first/last fragment of an {ib} split as FIRST/LAST_FRAGMENT_OF_ELEMENT. <!-- Please describe your changes on the following line: --> This change allows inline margins, borders, and padding to interact correctly with {ib} splits. --- <!-- 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 #14030 - [X] There are tests for these changes <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/14035) <!-- Reviewable:end -->
This commit is contained in:
commit
959dfe4a4f
5 changed files with 47 additions and 40 deletions
|
@ -30,7 +30,7 @@ use fragment::{InlineAbsoluteHypotheticalFragmentInfo, TableColumnFragmentInfo};
|
||||||
use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
|
use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
|
||||||
use fragment::WhitespaceStrippingResult;
|
use fragment::WhitespaceStrippingResult;
|
||||||
use gfx::display_list::OpaqueNode;
|
use gfx::display_list::OpaqueNode;
|
||||||
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, InlineFragmentNodeFlags};
|
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow};
|
||||||
use inline::{InlineFragmentNodeInfo, LAST_FRAGMENT_OF_ELEMENT};
|
use inline::{InlineFragmentNodeInfo, LAST_FRAGMENT_OF_ELEMENT};
|
||||||
use linked_list::prepend_from;
|
use linked_list::prepend_from;
|
||||||
use list_item::{ListItemFlow, ListStyleTypeContent};
|
use list_item::{ListItemFlow, ListStyleTypeContent};
|
||||||
|
@ -161,6 +161,32 @@ pub struct InlineBlockSplit {
|
||||||
pub flow: FlowRef,
|
pub flow: FlowRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl InlineBlockSplit {
|
||||||
|
/// Flushes the given accumulator to the new split and makes a new accumulator to hold any
|
||||||
|
/// subsequent fragments.
|
||||||
|
fn new<ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>(fragment_accumulator: &mut InlineFragmentsAccumulator,
|
||||||
|
node: &ConcreteThreadSafeLayoutNode,
|
||||||
|
style_context: &SharedStyleContext,
|
||||||
|
flow: FlowRef)
|
||||||
|
-> InlineBlockSplit {
|
||||||
|
fragment_accumulator.enclosing_node.as_mut().expect(
|
||||||
|
"enclosing_node is None; Are {ib} splits being generated outside of an inline node?"
|
||||||
|
).flags.remove(LAST_FRAGMENT_OF_ELEMENT);
|
||||||
|
|
||||||
|
let split = InlineBlockSplit {
|
||||||
|
predecessors: mem::replace(
|
||||||
|
fragment_accumulator,
|
||||||
|
InlineFragmentsAccumulator::from_inline_node(
|
||||||
|
node, style_context)).to_intermediate_inline_fragments(),
|
||||||
|
flow: flow,
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment_accumulator.enclosing_node.as_mut().unwrap().flags.remove(FIRST_FRAGMENT_OF_ELEMENT);
|
||||||
|
|
||||||
|
split
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Holds inline fragments and absolute descendants.
|
/// Holds inline fragments and absolute descendants.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct IntermediateInlineFragments {
|
pub struct IntermediateInlineFragments {
|
||||||
|
@ -194,8 +220,14 @@ struct InlineFragmentsAccumulator {
|
||||||
/// The list of fragments.
|
/// The list of fragments.
|
||||||
fragments: IntermediateInlineFragments,
|
fragments: IntermediateInlineFragments,
|
||||||
|
|
||||||
/// Whether we've created a range to enclose all the fragments. This will be Some() if the
|
/// Information about the inline box directly enclosing the fragments being gathered, if any.
|
||||||
/// outer node is an inline and None otherwise.
|
///
|
||||||
|
/// `inline::InlineFragmentNodeInfo` also stores flags indicating whether a fragment is the
|
||||||
|
/// first and/or last of the corresponding inline box. This `InlineFragmentsAccumulator` may
|
||||||
|
/// represent only one side of an {ib} split, so we store these flags as if it represented only
|
||||||
|
/// one fragment. `to_intermediate_inline_fragments` later splits this hypothetical fragment
|
||||||
|
/// into pieces, leaving the `FIRST_FRAGMENT_OF_ELEMENT` and `LAST_FRAGMENT_OF_ELEMENT` flags,
|
||||||
|
/// if present, on the first and last fragments of the output.
|
||||||
enclosing_node: Option<InlineFragmentNodeInfo>,
|
enclosing_node: Option<InlineFragmentNodeInfo>,
|
||||||
|
|
||||||
/// Restyle damage to use for fragments created in this node.
|
/// Restyle damage to use for fragments created in this node.
|
||||||
|
@ -224,7 +256,7 @@ impl InlineFragmentsAccumulator {
|
||||||
pseudo: node.get_pseudo_element_type().strip(),
|
pseudo: node.get_pseudo_element_type().strip(),
|
||||||
style: node.style(style_context),
|
style: node.style(style_context),
|
||||||
selected_style: node.selected_style(),
|
selected_style: node.selected_style(),
|
||||||
flags: InlineFragmentNodeFlags::empty(),
|
flags: FIRST_FRAGMENT_OF_ELEMENT | LAST_FRAGMENT_OF_ELEMENT,
|
||||||
}),
|
}),
|
||||||
bidi_control_chars: None,
|
bidi_control_chars: None,
|
||||||
restyle_damage: node.restyle_damage(),
|
restyle_damage: node.restyle_damage(),
|
||||||
|
@ -247,21 +279,23 @@ impl InlineFragmentsAccumulator {
|
||||||
bidi_control_chars,
|
bidi_control_chars,
|
||||||
restyle_damage,
|
restyle_damage,
|
||||||
} = self;
|
} = self;
|
||||||
if let Some(enclosing_node) = enclosing_node {
|
if let Some(mut enclosing_node) = enclosing_node {
|
||||||
let fragment_count = fragments.fragments.len();
|
let fragment_count = fragments.fragments.len();
|
||||||
for (index, fragment) in fragments.fragments.iter_mut().enumerate() {
|
for (index, fragment) in fragments.fragments.iter_mut().enumerate() {
|
||||||
let mut enclosing_node = enclosing_node.clone();
|
let mut enclosing_node = enclosing_node.clone();
|
||||||
if index == 0 {
|
if index != 0 {
|
||||||
enclosing_node.flags.insert(FIRST_FRAGMENT_OF_ELEMENT)
|
enclosing_node.flags.remove(FIRST_FRAGMENT_OF_ELEMENT)
|
||||||
}
|
}
|
||||||
if index == fragment_count - 1 {
|
if index != fragment_count - 1 {
|
||||||
enclosing_node.flags.insert(LAST_FRAGMENT_OF_ELEMENT)
|
enclosing_node.flags.remove(LAST_FRAGMENT_OF_ELEMENT)
|
||||||
}
|
}
|
||||||
fragment.add_inline_context_style(enclosing_node);
|
fragment.add_inline_context_style(enclosing_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control characters are later discarded in transform_text, so they don't affect the
|
// Control characters are later discarded in transform_text, so they don't affect the
|
||||||
// is_first/is_last styles above.
|
// is_first/is_last styles above.
|
||||||
|
enclosing_node.flags.remove(FIRST_FRAGMENT_OF_ELEMENT | LAST_FRAGMENT_OF_ELEMENT);
|
||||||
|
|
||||||
if let Some((start, end)) = bidi_control_chars {
|
if let Some((start, end)) = bidi_control_chars {
|
||||||
fragments.fragments.push_front(
|
fragments.fragments.push_front(
|
||||||
control_chars_to_fragment(&enclosing_node, start, restyle_damage));
|
control_chars_to_fragment(&enclosing_node, start, restyle_damage));
|
||||||
|
@ -717,14 +751,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
|
||||||
} = split;
|
} = split;
|
||||||
fragment_accumulator.push_all(predecessors);
|
fragment_accumulator.push_all(predecessors);
|
||||||
|
|
||||||
let split = InlineBlockSplit {
|
opt_inline_block_splits.push_back(
|
||||||
predecessors: mem::replace(
|
InlineBlockSplit::new(fragment_accumulator, node, self.style_context(), kid_flow));
|
||||||
fragment_accumulator,
|
|
||||||
InlineFragmentsAccumulator::from_inline_node(
|
|
||||||
node, self.style_context())).to_intermediate_inline_fragments(),
|
|
||||||
flow: kid_flow,
|
|
||||||
};
|
|
||||||
opt_inline_block_splits.push_back(split)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,17 +779,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
|
||||||
ConstructionResult::None => {}
|
ConstructionResult::None => {}
|
||||||
ConstructionResult::Flow(flow, kid_abs_descendants) => {
|
ConstructionResult::Flow(flow, kid_abs_descendants) => {
|
||||||
if !flow::base(&*flow).flags.contains(IS_ABSOLUTELY_POSITIONED) {
|
if !flow::base(&*flow).flags.contains(IS_ABSOLUTELY_POSITIONED) {
|
||||||
// {ib} split. Flush the accumulator to our new split and make a new
|
opt_inline_block_splits.push_back(InlineBlockSplit::new(
|
||||||
// accumulator to hold any subsequent fragments we come across.
|
&mut fragment_accumulator, node, self.style_context(), flow));
|
||||||
let split = InlineBlockSplit {
|
|
||||||
predecessors:
|
|
||||||
mem::replace(
|
|
||||||
&mut fragment_accumulator,
|
|
||||||
InlineFragmentsAccumulator::from_inline_node(
|
|
||||||
node, self.style_context())).to_intermediate_inline_fragments(),
|
|
||||||
flow: flow,
|
|
||||||
};
|
|
||||||
opt_inline_block_splits.push_back(split);
|
|
||||||
abs_descendants.push_descendants(kid_abs_descendants);
|
abs_descendants.push_descendants(kid_abs_descendants);
|
||||||
} else {
|
} else {
|
||||||
// Push the absolutely-positioned kid as an inline containing block.
|
// Push the absolutely-positioned kid as an inline containing block.
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[block-in-inline-insert-017.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[inline-box-001.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[ltr-ib.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[rtl-ib.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue