aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020/flow
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout_2020/flow')
-rw-r--r--components/layout_2020/flow/construct.rs222
-rw-r--r--components/layout_2020/flow/float.rs3
-rw-r--r--components/layout_2020/flow/inline.rs197
-rw-r--r--components/layout_2020/flow/mod.rs54
-rw-r--r--components/layout_2020/flow/root.rs138
5 files changed, 376 insertions, 238 deletions
diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs
index cff3fa281a6..fe9465f775e 100644
--- a/components/layout_2020/flow/construct.rs
+++ b/components/layout_2020/flow/construct.rs
@@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::dom_traversal::{BoxSlot, Contents, NodeExt, NonReplacedContents, TraversalHandler};
use crate::element_data::LayoutBox;
@@ -18,6 +19,7 @@ use servo_arc::Arc;
use std::convert::{TryFrom, TryInto};
use style::properties::ComputedValues;
use style::selector_parser::PseudoElement;
+use style::values::specified::text::TextDecorationLine;
impl BlockFormattingContext {
pub fn construct<'dom>(
@@ -26,9 +28,16 @@ impl BlockFormattingContext {
style: &Arc<ComputedValues>,
contents: NonReplacedContents,
content_sizes: ContentSizesRequest,
+ propagated_text_decoration_line: TextDecorationLine,
) -> (Self, BoxContentSizes) {
- let (contents, contains_floats, inline_content_sizes) =
- BlockContainer::construct(context, node, style, contents, content_sizes);
+ let (contents, contains_floats, inline_content_sizes) = BlockContainer::construct(
+ context,
+ node,
+ style,
+ contents,
+ content_sizes,
+ propagated_text_decoration_line,
+ );
// FIXME: add contribution to `inline_content_sizes` of floats in this formatting context
// https://dbaron.org/css/intrinsic/#intrinsic
let bfc = Self {
@@ -51,6 +60,7 @@ enum BlockLevelCreator {
Independent {
display_inside: DisplayInside,
contents: Contents,
+ propagated_text_decoration_line: TextDecorationLine,
},
OutOfFlowAbsolutelyPositionedBox {
display_inside: DisplayInside,
@@ -71,7 +81,7 @@ enum BlockLevelCreator {
/// Deferring allows using rayon’s `into_par_iter`.
enum IntermediateBlockContainer {
InlineFormattingContext(InlineFormattingContext),
- Deferred(NonReplacedContents),
+ Deferred(NonReplacedContents, TextDecorationLine),
}
/// A builder for a block container.
@@ -139,13 +149,16 @@ impl BlockContainer {
block_container_style: &Arc<ComputedValues>,
contents: NonReplacedContents,
content_sizes: ContentSizesRequest,
+ propagated_text_decoration_line: TextDecorationLine,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
+ let text_decoration_line =
+ propagated_text_decoration_line | block_container_style.clone_text_decoration_line();
let mut builder = BlockContainerBuilder {
context,
root,
block_container_style,
block_level_boxes: Vec::new(),
- ongoing_inline_formatting_context: InlineFormattingContext::default(),
+ ongoing_inline_formatting_context: InlineFormattingContext::new(text_decoration_line),
ongoing_inline_boxes_stack: Vec::new(),
anonymous_style: None,
contains_floats: ContainsFloats::No,
@@ -282,54 +295,48 @@ where
// context with the parent style of that builder.
let inlines = self.current_inline_level_boxes();
- fn last_text(inlines: &mut [Arc<InlineLevelBox>]) -> Option<&mut String> {
- let last = inlines.last_mut()?;
- if let InlineLevelBox::TextRun(_) = &**last {
- // We never clone text run boxes, so the refcount is 1 and unwrap succeeds:
- let last = Arc::get_mut(last).unwrap();
- if let InlineLevelBox::TextRun(TextRun { text, .. }) = last {
- Some(text)
- } else {
- unreachable!()
- }
- } else {
- None
- }
- }
-
let mut new_text_run_contents;
let output;
- if let Some(text) = last_text(inlines) {
- // Append to the existing text run
- new_text_run_contents = None;
- output = text;
- } else {
- new_text_run_contents = Some(String::new());
- output = new_text_run_contents.as_mut().unwrap();
- }
- if leading_whitespace {
- output.push(' ')
- }
- loop {
- if let Some(i) = input.bytes().position(|b| b.is_ascii_whitespace()) {
- let (non_whitespace, rest) = input.split_at(i);
- output.push_str(non_whitespace);
- output.push(' ');
- if let Some(i) = rest.bytes().position(|b| !b.is_ascii_whitespace()) {
- input = &rest[i..];
+ {
+ let mut last_box = inlines.last_mut().map(|last| last.borrow_mut());
+ let last_text = last_box.as_mut().and_then(|last| match &mut **last {
+ InlineLevelBox::TextRun(last) => Some(&mut last.text),
+ _ => None,
+ });
+
+ if let Some(text) = last_text {
+ // Append to the existing text run
+ new_text_run_contents = None;
+ output = text;
+ } else {
+ new_text_run_contents = Some(String::new());
+ output = new_text_run_contents.as_mut().unwrap();
+ }
+
+ if leading_whitespace {
+ output.push(' ')
+ }
+ loop {
+ if let Some(i) = input.bytes().position(|b| b.is_ascii_whitespace()) {
+ let (non_whitespace, rest) = input.split_at(i);
+ output.push_str(non_whitespace);
+ output.push(' ');
+ if let Some(i) = rest.bytes().position(|b| !b.is_ascii_whitespace()) {
+ input = &rest[i..];
+ } else {
+ break;
+ }
} else {
+ output.push_str(input);
break;
}
- } else {
- output.push_str(input);
- break;
}
}
if let Some(text) = new_text_run_contents {
let parent_style = parent_style.clone();
- inlines.push(Arc::new(InlineLevelBox::TextRun(TextRun {
+ inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun {
tag: node.as_opaque(),
parent_style,
text,
@@ -353,29 +360,53 @@ where
if !text.starts_with(|c: char| c.is_ascii_whitespace()) {
return (false, text);
}
- let mut inline_level_boxes = self.current_inline_level_boxes().iter().rev();
- let mut stack = Vec::new();
- let preserved = loop {
- match inline_level_boxes.next().map(|b| &**b) {
- Some(InlineLevelBox::TextRun(r)) => break !r.text.ends_with(' '),
- Some(InlineLevelBox::Atomic { .. }) => break false,
- Some(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(_)) |
- Some(InlineLevelBox::OutOfFlowFloatBox(_)) => {},
- Some(InlineLevelBox::InlineBox(b)) => {
- stack.push(inline_level_boxes);
- inline_level_boxes = b.children.iter().rev()
- },
- None => {
- if let Some(iter) = stack.pop() {
- inline_level_boxes = iter
- } else {
- break false; // Paragraph start
- }
- },
- }
+
+ let preserved = match whitespace_is_preserved(self.current_inline_level_boxes()) {
+ WhitespacePreservedResult::Unknown => {
+ // Paragraph start.
+ false
+ },
+ WhitespacePreservedResult::NotPreserved => false,
+ WhitespacePreservedResult::Preserved => true,
};
+
let text = text.trim_start_matches(|c: char| c.is_ascii_whitespace());
- (preserved, text)
+ return (preserved, text);
+
+ fn whitespace_is_preserved(
+ inline_level_boxes: &[ArcRefCell<InlineLevelBox>],
+ ) -> WhitespacePreservedResult {
+ for inline_level_box in inline_level_boxes.iter().rev() {
+ match *inline_level_box.borrow() {
+ InlineLevelBox::TextRun(ref r) => {
+ if r.text.ends_with(' ') {
+ return WhitespacePreservedResult::NotPreserved;
+ }
+ return WhitespacePreservedResult::Preserved;
+ },
+ InlineLevelBox::Atomic { .. } => {
+ return WhitespacePreservedResult::NotPreserved;
+ },
+ InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(_) |
+ InlineLevelBox::OutOfFlowFloatBox(_) => {},
+ InlineLevelBox::InlineBox(ref b) => {
+ match whitespace_is_preserved(&b.children) {
+ WhitespacePreservedResult::Unknown => {},
+ result => return result,
+ }
+ },
+ }
+ }
+
+ WhitespacePreservedResult::Unknown
+ }
+
+ #[derive(Clone, Copy, PartialEq)]
+ enum WhitespacePreservedResult {
+ Preserved,
+ NotPreserved,
+ Unknown,
+ }
}
fn handle_inline_level_element(
@@ -384,7 +415,7 @@ where
style: &Arc<ComputedValues>,
display_inside: DisplayInside,
contents: Contents,
- ) -> Arc<InlineLevelBox> {
+ ) -> ArcRefCell<InlineLevelBox> {
let box_ = if display_inside == DisplayInside::Flow && !contents.is_replaced() {
// We found un inline box.
// Whatever happened before, all we need to do before recurring
@@ -410,9 +441,9 @@ where
.pop()
.expect("no ongoing inline level box found");
inline_box.last_fragment = true;
- Arc::new(InlineLevelBox::InlineBox(inline_box))
+ ArcRefCell::new(InlineLevelBox::InlineBox(inline_box))
} else {
- Arc::new(InlineLevelBox::Atomic(
+ ArcRefCell::new(InlineLevelBox::Atomic(
IndependentFormattingContext::construct(
self.context,
node,
@@ -420,6 +451,8 @@ where
display_inside,
contents,
ContentSizesRequest::inline_if(!style.inline_size_is_length()),
+ // Text decorations are not propagated to atomic inline-level descendants.
+ TextDecorationLine::NONE,
),
))
};
@@ -466,15 +499,18 @@ where
for mut fragmented_parent_inline_box in fragmented_inline_boxes {
fragmented_parent_inline_box
.children
- .push(Arc::new(fragmented_inline));
+ .push(ArcRefCell::new(fragmented_inline));
fragmented_inline = InlineLevelBox::InlineBox(fragmented_parent_inline_box);
}
self.ongoing_inline_formatting_context
.inline_level_boxes
- .push(Arc::new(fragmented_inline));
+ .push(ArcRefCell::new(fragmented_inline));
}
+ let propagated_text_decoration_line =
+ self.ongoing_inline_formatting_context.text_decoration_line;
+
// We found a block level element, so the ongoing inline formatting
// context needs to be ended.
self.end_ongoing_inline_formatting_context();
@@ -482,11 +518,12 @@ where
let kind = match contents.try_into() {
Ok(contents) => match display_inside {
DisplayInside::Flow => BlockLevelCreator::SameFormattingContextBlock(
- IntermediateBlockContainer::Deferred(contents),
+ IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line),
),
_ => BlockLevelCreator::Independent {
display_inside,
contents: contents.into(),
+ propagated_text_decoration_line,
},
},
Err(contents) => {
@@ -494,6 +531,7 @@ where
BlockLevelCreator::Independent {
display_inside,
contents,
+ propagated_text_decoration_line,
}
},
};
@@ -525,7 +563,7 @@ where
kind,
});
} else {
- let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(
+ let box_ = ArcRefCell::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
AbsolutelyPositionedBox::construct(
self.context,
node,
@@ -533,7 +571,7 @@ where
display_inside,
contents,
),
- ));
+ )));
self.current_inline_level_boxes().push(box_.clone());
box_slot.set(LayoutBox::InlineLevel(box_))
}
@@ -561,7 +599,7 @@ where
kind,
});
} else {
- let box_ = Arc::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct(
+ let box_ = ArcRefCell::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct(
self.context,
node,
style,
@@ -610,7 +648,7 @@ where
});
}
- fn current_inline_level_boxes(&mut self) -> &mut Vec<Arc<InlineLevelBox>> {
+ fn current_inline_level_boxes(&mut self) -> &mut Vec<ArcRefCell<InlineLevelBox>> {
match self.ongoing_inline_boxes_stack.last_mut() {
Some(last) => &mut last.children,
None => &mut self.ongoing_inline_formatting_context.inline_level_boxes,
@@ -634,7 +672,7 @@ where
self,
context: &LayoutContext,
max_assign_in_flow_outer_content_sizes_to: Option<&mut ContentSizes>,
- ) -> (Arc<BlockLevelBox>, ContainsFloats) {
+ ) -> (ArcRefCell<BlockLevelBox>, ContainsFloats) {
let node = self.node;
let style = self.style;
let (block_level_box, contains_floats) = match self.kind {
@@ -651,7 +689,7 @@ where
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
to.max_assign(&box_content_sizes.outer_inline(&style))
}
- let block_level_box = Arc::new(BlockLevelBox::SameFormattingContextBlock {
+ let block_level_box = ArcRefCell::new(BlockLevelBox::SameFormattingContextBlock {
tag: node.as_opaque(),
contents,
style,
@@ -661,6 +699,7 @@ where
BlockLevelCreator::Independent {
display_inside,
contents,
+ propagated_text_decoration_line,
} => {
let content_sizes = ContentSizesRequest::inline_if(
max_assign_in_flow_outer_content_sizes_to.is_some() &&
@@ -673,12 +712,13 @@ where
display_inside,
contents,
content_sizes,
+ propagated_text_decoration_line,
);
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
to.max_assign(&contents.content_sizes.outer_inline(&contents.style))
}
(
- Arc::new(BlockLevelBox::Independent(contents)),
+ ArcRefCell::new(BlockLevelBox::Independent(contents)),
ContainsFloats::No,
)
},
@@ -686,22 +726,23 @@ where
display_inside,
contents,
} => {
- let block_level_box = Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
- AbsolutelyPositionedBox::construct(
- context,
- node,
- style,
- display_inside,
- contents,
- ),
- ));
+ let block_level_box =
+ ArcRefCell::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
+ AbsolutelyPositionedBox::construct(
+ context,
+ node,
+ style,
+ display_inside,
+ contents,
+ ),
+ )));
(block_level_box, ContainsFloats::No)
},
BlockLevelCreator::OutOfFlowFloatBox {
display_inside,
contents,
} => {
- let block_level_box = Arc::new(BlockLevelBox::OutOfFlowFloatBox(
+ let block_level_box = ArcRefCell::new(BlockLevelBox::OutOfFlowFloatBox(
FloatBox::construct(context, node, style, display_inside, contents),
));
(block_level_box, ContainsFloats::Yes)
@@ -722,8 +763,15 @@ impl IntermediateBlockContainer {
content_sizes: ContentSizesRequest,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
match self {
- IntermediateBlockContainer::Deferred(contents) => {
- BlockContainer::construct(context, node, style, contents, content_sizes)
+ IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line) => {
+ BlockContainer::construct(
+ context,
+ node,
+ style,
+ contents,
+ content_sizes,
+ propagated_text_decoration_line,
+ )
},
IntermediateBlockContainer::InlineFormattingContext(ifc) => {
let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context));
diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs
index 5b34392ac8c..4a647f23071 100644
--- a/components/layout_2020/flow/float.rs
+++ b/components/layout_2020/flow/float.rs
@@ -9,6 +9,7 @@ use crate::sizing::ContentSizesRequest;
use crate::style_ext::{ComputedValuesExt, DisplayInside};
use servo_arc::Arc;
use style::properties::ComputedValues;
+use style::values::specified::text::TextDecorationLine;
#[derive(Debug, Serialize)]
pub(crate) struct FloatBox {
@@ -43,6 +44,8 @@ impl FloatBox {
display_inside,
contents,
content_sizes,
+ // Text decorations are not propagated to any out-of-flow descendants
+ TextDecorationLine::NONE,
),
}
}
diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs
index bd8f5bc784f..6588a6a3137 100644
--- a/components/layout_2020/flow/inline.rs
+++ b/components/layout_2020/flow/inline.rs
@@ -2,16 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::flow::float::FloatBox;
use crate::flow::FlowLayout;
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{
AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins,
- DebugId, Fragment, TextFragment,
+ DebugId, FontMetrics, Fragment, TextFragment,
};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
-use crate::positioned::{relative_adjustement, AbsolutelyPositionedBox, PositioningContext};
+use crate::positioned::{
+ relative_adjustement, AbsolutelyPositionedBox, HoistedAbsolutelyPositionedBox,
+ PositioningContext,
+};
use crate::sizing::ContentSizes;
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
use crate::ContainingBlock;
@@ -22,19 +26,21 @@ use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthPercentage, Percentage};
use style::values::specified::text::TextAlignKeyword;
+use style::values::specified::text::TextDecorationLine;
use style::Zero;
use webrender_api::FontInstanceKey;
#[derive(Debug, Default, Serialize)]
pub(crate) struct InlineFormattingContext {
- pub(super) inline_level_boxes: Vec<Arc<InlineLevelBox>>,
+ pub(super) inline_level_boxes: Vec<ArcRefCell<InlineLevelBox>>,
+ pub(super) text_decoration_line: TextDecorationLine,
}
#[derive(Debug, Serialize)]
pub(crate) enum InlineLevelBox {
InlineBox(InlineBox),
TextRun(TextRun),
- OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox),
+ OutOfFlowAbsolutelyPositionedBox(Arc<AbsolutelyPositionedBox>),
OutOfFlowFloatBox(FloatBox),
Atomic(IndependentFormattingContext),
}
@@ -46,7 +52,7 @@ pub(crate) struct InlineBox {
pub style: Arc<ComputedValues>,
pub first_fragment: bool,
pub last_fragment: bool,
- pub children: Vec<Arc<InlineLevelBox>>,
+ pub children: Vec<ArcRefCell<InlineLevelBox>>,
}
/// https://www.w3.org/TR/css-display-3/#css-text-run
@@ -59,10 +65,16 @@ pub(crate) struct TextRun {
}
struct InlineNestingLevelState<'box_tree> {
- remaining_boxes: std::slice::Iter<'box_tree, Arc<InlineLevelBox>>,
+ remaining_boxes: InlineBoxChildIter<'box_tree>,
fragments_so_far: Vec<Fragment>,
inline_start: Length,
max_block_size_of_fragments_so_far: Length,
+ positioning_context: Option<PositioningContext>,
+ /// Indicates whether this nesting level have text decorations in effect.
+ /// From https://drafts.csswg.org/css-text-decor/#line-decoration
+ // "When specified on or propagated to a block container that establishes
+ // an IFC..."
+ text_decoration_line: TextDecorationLine,
}
struct PartialInlineBoxFragment<'box_tree> {
@@ -77,7 +89,7 @@ struct PartialInlineBoxFragment<'box_tree> {
}
struct InlineFormattingContextState<'box_tree, 'a, 'b> {
- positioning_context: &'a mut PositioningContext<'box_tree>,
+ positioning_context: &'a mut PositioningContext,
containing_block: &'b ContainingBlock<'b>,
lines: Lines,
inline_position: Length,
@@ -85,6 +97,31 @@ struct InlineFormattingContextState<'box_tree, 'a, 'b> {
current_nesting_level: InlineNestingLevelState<'box_tree>,
}
+impl<'box_tree, 'a, 'b> InlineFormattingContextState<'box_tree, 'a, 'b> {
+ fn push_hoisted_box_to_positioning_context(
+ &mut self,
+ hoisted_box: HoistedAbsolutelyPositionedBox,
+ ) {
+ if let Some(context) = self.current_nesting_level.positioning_context.as_mut() {
+ context.push(hoisted_box);
+ return;
+ }
+
+ for nesting_level in self.partial_inline_boxes_stack.iter_mut().rev() {
+ if let Some(context) = nesting_level
+ .parent_nesting_level
+ .positioning_context
+ .as_mut()
+ {
+ context.push(hoisted_box);
+ return;
+ }
+ }
+
+ self.positioning_context.push(hoisted_box);
+ }
+}
+
struct Lines {
// One anonymous fragment per line
fragments: Vec<Fragment>,
@@ -92,6 +129,13 @@ struct Lines {
}
impl InlineFormattingContext {
+ pub(super) fn new(text_decoration_line: TextDecorationLine) -> InlineFormattingContext {
+ InlineFormattingContext {
+ inline_level_boxes: Default::default(),
+ text_decoration_line,
+ }
+ }
+
// This works on an already-constructed `InlineFormattingContext`,
// Which would have to change if/when
// `BlockContainer::construct` parallelize their construction.
@@ -105,10 +149,10 @@ impl InlineFormattingContext {
fn traverse(
&mut self,
layout_context: &LayoutContext,
- inline_level_boxes: &[Arc<InlineLevelBox>],
+ inline_level_boxes: &[ArcRefCell<InlineLevelBox>],
) {
for inline_level_box in inline_level_boxes {
- match &**inline_level_box {
+ match &*inline_level_box.borrow() {
InlineLevelBox::InlineBox(inline_box) => {
let padding = inline_box.style.padding();
let border = inline_box.style.border_width();
@@ -204,10 +248,10 @@ impl InlineFormattingContext {
computation.paragraph
}
- pub(super) fn layout<'a>(
- &'a self,
+ pub(super) fn layout(
+ &self,
layout_context: &LayoutContext,
- positioning_context: &mut PositioningContext<'a>,
+ positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
tree_rank: usize,
) -> FlowLayout {
@@ -221,17 +265,20 @@ impl InlineFormattingContext {
},
inline_position: Length::zero(),
current_nesting_level: InlineNestingLevelState {
- remaining_boxes: self.inline_level_boxes.iter(),
+ remaining_boxes: InlineBoxChildIter::from_formatting_context(self),
fragments_so_far: Vec::with_capacity(self.inline_level_boxes.len()),
inline_start: Length::zero(),
max_block_size_of_fragments_so_far: Length::zero(),
+ positioning_context: None,
+ text_decoration_line: self.text_decoration_line,
},
};
+
loop {
if let Some(child) = ifc.current_nesting_level.remaining_boxes.next() {
- match &**child {
+ match &*child.borrow() {
InlineLevelBox::InlineBox(inline) => {
- let partial = inline.start_layout(&mut ifc);
+ let partial = inline.start_layout(child.clone(), &mut ifc);
ifc.partial_inline_boxes_stack.push(partial)
},
InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc),
@@ -256,14 +303,17 @@ impl InlineFormattingContext {
panic!("display:none does not generate an abspos box")
},
};
- let hoisted_fragment = box_.to_hoisted(initial_start_corner, tree_rank);
- let hoisted_fragment_id = hoisted_fragment.fragment_id;
- ifc.positioning_context.push(hoisted_fragment);
- ifc.lines
- .fragments
- .push(Fragment::AbsoluteOrFixedPositioned(
- AbsoluteOrFixedPositionedFragment(hoisted_fragment_id),
- ));
+ let hoisted_box = box_.clone().to_hoisted(initial_start_corner, tree_rank);
+ let hoisted_fragment = hoisted_box.fragment.clone();
+ ifc.push_hoisted_box_to_positioning_context(hoisted_box);
+ ifc.current_nesting_level.fragments_so_far.push(
+ Fragment::AbsoluteOrFixedPositioned(
+ AbsoluteOrFixedPositionedFragment {
+ hoisted_fragment,
+ position: box_.contents.style.clone_position(),
+ },
+ ),
+ );
},
InlineLevelBox::OutOfFlowFloatBox(_box_) => {
// TODO
@@ -273,6 +323,7 @@ impl InlineFormattingContext {
// Reached the end of ifc.remaining_boxes
if let Some(mut partial) = ifc.partial_inline_boxes_stack.pop() {
partial.finish_layout(
+ layout_context,
&mut ifc.current_nesting_level,
&mut ifc.inline_position,
false,
@@ -353,6 +404,7 @@ impl Lines {
block: line_block_size,
};
self.next_line_block_position += size.block;
+
self.fragments
.push(Fragment::Anonymous(AnonymousFragment::new(
Rect { start_corner, size },
@@ -364,7 +416,8 @@ impl Lines {
impl InlineBox {
fn start_layout<'box_tree>(
- &'box_tree self,
+ &self,
+ this_inline_level_box: ArcRefCell<InlineLevelBox>,
ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>,
) -> PartialInlineBoxFragment<'box_tree> {
let style = self.style.clone();
@@ -389,6 +442,9 @@ impl InlineBox {
if style.clone_position().is_relative() {
start_corner += &relative_adjustement(&style, ifc.containing_block)
}
+ let positioning_context = PositioningContext::new_for_style(&style);
+ let text_decoration_line =
+ ifc.current_nesting_level.text_decoration_line | style.clone_text_decoration_line();
PartialInlineBoxFragment {
tag: self.tag,
style,
@@ -400,10 +456,14 @@ impl InlineBox {
parent_nesting_level: std::mem::replace(
&mut ifc.current_nesting_level,
InlineNestingLevelState {
- remaining_boxes: self.children.iter(),
+ remaining_boxes: InlineBoxChildIter::from_inline_level_box(
+ this_inline_level_box,
+ ),
fragments_so_far: Vec::with_capacity(self.children.len()),
inline_start: ifc.inline_position,
max_block_size_of_fragments_so_far: Length::zero(),
+ positioning_context,
+ text_decoration_line: text_decoration_line,
},
),
}
@@ -413,6 +473,7 @@ impl InlineBox {
impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
fn finish_layout(
&mut self,
+ layout_context: &LayoutContext,
nesting_level: &mut InlineNestingLevelState,
inline_position: &mut Length,
at_line_break: bool,
@@ -434,7 +495,6 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
self.border.clone(),
self.margin.clone(),
CollapsedBlockMargins::zero(),
- None, // hoisted_fragment_id
);
let last_fragment = self.last_box_tree_fragment && !at_line_break;
if last_fragment {
@@ -454,16 +514,21 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
fragment.border.block_sum() +
fragment.margin.block_sum(),
);
+
+ if let Some(context) = nesting_level.positioning_context.as_mut() {
+ context.layout_collected_children(layout_context, &mut fragment);
+ }
+
self.parent_nesting_level
.fragments_so_far
.push(Fragment::Box(fragment));
}
}
-fn layout_atomic<'box_tree>(
+fn layout_atomic(
layout_context: &LayoutContext,
- ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>,
- atomic: &'box_tree IndependentFormattingContext,
+ ifc: &mut InlineFormattingContextState,
+ atomic: &IndependentFormattingContext,
) {
let cbis = ifc.containing_block.inline_size;
let padding = atomic.style.padding().percentages_relative_to(cbis);
@@ -497,7 +562,6 @@ fn layout_atomic<'box_tree>(
border,
margin,
CollapsedBlockMargins::zero(),
- None, // hoisted_fragment_id
)
},
Err(non_replaced) => {
@@ -573,7 +637,6 @@ fn layout_atomic<'box_tree>(
border,
margin,
CollapsedBlockMargins::zero(),
- None, // hoisted_fragment_id
)
},
};
@@ -588,8 +651,7 @@ fn layout_atomic<'box_tree>(
}
struct BreakAndShapeResult {
- font_ascent: Au,
- font_line_gap: Au,
+ font_metrics: FontMetrics,
font_key: FontInstanceKey,
runs: Vec<GlyphRun>,
break_at_start: bool,
@@ -656,8 +718,7 @@ impl TextRun {
);
BreakAndShapeResult {
- font_ascent: font.metrics.ascent,
- font_line_gap: font.metrics.line_gap,
+ font_metrics: (&font.metrics).into(),
font_key: font.font_key,
runs,
break_at_start,
@@ -669,8 +730,7 @@ impl TextRun {
use style::values::generics::text::LineHeight;
let BreakAndShapeResult {
- font_ascent,
- font_line_gap,
+ font_metrics,
font_key,
runs,
break_at_start: _,
@@ -707,7 +767,7 @@ impl TextRun {
}
}
let line_height = match self.parent_style.get_inherited_text().line_height {
- LineHeight::Normal => font_line_gap.into(),
+ LineHeight::Normal => font_metrics.line_gap,
LineHeight::Number(n) => font_size * n.0,
LineHeight::Length(l) => l.0,
};
@@ -732,9 +792,10 @@ impl TextRun {
debug_id: DebugId::new(),
parent_style: self.parent_style.clone(),
rect,
- ascent: font_ascent.into(),
+ font_metrics,
font_key,
glyphs,
+ text_decoration_line: ifc.current_nesting_level.text_decoration_line,
}));
if runs.is_empty() {
break;
@@ -743,7 +804,12 @@ impl TextRun {
ifc.current_nesting_level.inline_start = Length::zero();
let mut nesting_level = &mut ifc.current_nesting_level;
for partial in ifc.partial_inline_boxes_stack.iter_mut().rev() {
- partial.finish_layout(nesting_level, &mut ifc.inline_position, true);
+ partial.finish_layout(
+ layout_context,
+ nesting_level,
+ &mut ifc.inline_position,
+ true,
+ );
partial.start_corner.inline = Length::zero();
partial.padding.inline_start = Length::zero();
partial.border.inline_start = Length::zero();
@@ -758,3 +824,54 @@ impl TextRun {
}
}
}
+
+enum InlineBoxChildIter<'box_tree> {
+ InlineFormattingContext(std::slice::Iter<'box_tree, ArcRefCell<InlineLevelBox>>),
+ InlineBox {
+ inline_level_box: ArcRefCell<InlineLevelBox>,
+ child_index: usize,
+ },
+}
+
+impl<'box_tree> InlineBoxChildIter<'box_tree> {
+ fn from_formatting_context(
+ inline_formatting_context: &'box_tree InlineFormattingContext,
+ ) -> InlineBoxChildIter<'box_tree> {
+ InlineBoxChildIter::InlineFormattingContext(
+ inline_formatting_context.inline_level_boxes.iter(),
+ )
+ }
+
+ fn from_inline_level_box(
+ inline_level_box: ArcRefCell<InlineLevelBox>,
+ ) -> InlineBoxChildIter<'box_tree> {
+ InlineBoxChildIter::InlineBox {
+ inline_level_box,
+ child_index: 0,
+ }
+ }
+}
+
+impl<'box_tree> Iterator for InlineBoxChildIter<'box_tree> {
+ type Item = ArcRefCell<InlineLevelBox>;
+ fn next(&mut self) -> Option<ArcRefCell<InlineLevelBox>> {
+ match *self {
+ InlineBoxChildIter::InlineFormattingContext(ref mut iter) => iter.next().cloned(),
+ InlineBoxChildIter::InlineBox {
+ ref inline_level_box,
+ ref mut child_index,
+ } => match *inline_level_box.borrow() {
+ InlineLevelBox::InlineBox(ref inline_box) => {
+ if *child_index >= inline_box.children.len() {
+ return None;
+ }
+
+ let kid = inline_box.children[*child_index].clone();
+ *child_index += 1;
+ Some(kid)
+ },
+ _ => unreachable!(),
+ },
+ }
+ }
+}
diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs
index e15947f52b0..dcf2f9c4de3 100644
--- a/components/layout_2020/flow/mod.rs
+++ b/components/layout_2020/flow/mod.rs
@@ -4,6 +4,7 @@
//! Flow layout, also known as block-and-inline layout.
+use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::flow::float::{FloatBox, FloatContext};
use crate::flow::inline::InlineFormattingContext;
@@ -38,7 +39,7 @@ pub(crate) struct BlockFormattingContext {
#[derive(Debug, Serialize)]
pub(crate) enum BlockContainer {
- BlockLevelBoxes(Vec<Arc<BlockLevelBox>>),
+ BlockLevelBoxes(Vec<ArcRefCell<BlockLevelBox>>),
InlineFormattingContext(InlineFormattingContext),
}
@@ -50,7 +51,7 @@ pub(crate) enum BlockLevelBox {
style: Arc<ComputedValues>,
contents: BlockContainer,
},
- OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox),
+ OutOfFlowAbsolutelyPositionedBox(Arc<AbsolutelyPositionedBox>),
OutOfFlowFloatBox(FloatBox),
Independent(IndependentFormattingContext),
}
@@ -65,10 +66,10 @@ struct FlowLayout {
struct CollapsibleWithParentStartMargin(bool);
impl BlockFormattingContext {
- pub(super) fn layout<'a>(
- &'a self,
+ pub(super) fn layout(
+ &self,
layout_context: &LayoutContext,
- positioning_context: &mut PositioningContext<'a>,
+ positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
tree_rank: usize,
) -> IndependentLayout {
@@ -101,10 +102,10 @@ impl BlockFormattingContext {
}
impl BlockContainer {
- fn layout<'a>(
- &'a self,
+ fn layout(
+ &self,
layout_context: &LayoutContext,
- positioning_context: &mut PositioningContext<'a>,
+ positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
tree_rank: usize,
float_context: Option<&mut FloatContext>,
@@ -130,10 +131,10 @@ impl BlockContainer {
}
}
-fn layout_block_level_children<'a>(
+fn layout_block_level_children(
layout_context: &LayoutContext,
- positioning_context: &mut PositioningContext<'a>,
- child_boxes: &'a [Arc<BlockLevelBox>],
+ positioning_context: &mut PositioningContext,
+ child_boxes: &[ArcRefCell<BlockLevelBox>],
containing_block: &ContainingBlock,
tree_rank: usize,
mut float_context: Option<&mut FloatContext>,
@@ -204,7 +205,7 @@ fn layout_block_level_children<'a>(
.iter()
.enumerate()
.map(|(tree_rank, box_)| {
- let mut fragment = box_.layout(
+ let mut fragment = box_.borrow().layout(
layout_context,
positioning_context,
containing_block,
@@ -224,7 +225,7 @@ fn layout_block_level_children<'a>(
.mapfold_reduce_into(
positioning_context,
|positioning_context, (tree_rank, box_)| {
- box_.layout(
+ box_.borrow().layout(
layout_context,
positioning_context,
containing_block,
@@ -256,10 +257,10 @@ fn layout_block_level_children<'a>(
}
impl BlockLevelBox {
- fn layout<'a>(
- &'a self,
+ fn layout(
+ &self,
layout_context: &LayoutContext,
- positioning_context: &mut PositioningContext<'a>,
+ positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
tree_rank: usize,
float_context: Option<&mut FloatContext>,
@@ -314,12 +315,13 @@ impl BlockLevelBox {
))
},
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
- let hoisted_fragment = box_.to_hoisted(Vec2::zero(), tree_rank);
- let hoisted_fragment_id = hoisted_fragment.fragment_id.clone();
- positioning_context.push(hoisted_fragment);
- Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment(
- hoisted_fragment_id,
- ))
+ let hoisted_box = box_.clone().to_hoisted(Vec2::zero(), tree_rank);
+ let hoisted_fragment = hoisted_box.fragment.clone();
+ positioning_context.push(hoisted_box);
+ Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment {
+ hoisted_fragment,
+ position: box_.contents.style.clone_position(),
+ })
},
BlockLevelBox::OutOfFlowFloatBox(_box_) => {
// FIXME: call layout_maybe_position_relative_fragment here
@@ -338,13 +340,13 @@ enum NonReplacedContents<'a> {
/// https://drafts.csswg.org/css2/visudet.html#blockwidth
/// https://drafts.csswg.org/css2/visudet.html#normal-block
-fn layout_in_flow_non_replaced_block_level<'a>(
+fn layout_in_flow_non_replaced_block_level(
layout_context: &LayoutContext,
- positioning_context: &mut PositioningContext<'a>,
+ positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
tag: OpaqueNode,
style: &Arc<ComputedValues>,
- block_level_kind: NonReplacedContents<'a>,
+ block_level_kind: NonReplacedContents,
tree_rank: usize,
float_context: Option<&mut FloatContext>,
) -> BoxFragment {
@@ -500,7 +502,6 @@ fn layout_in_flow_non_replaced_block_level<'a>(
border,
margin,
block_margins_collapsed_with_children,
- None, // hoisted_fragment_id
)
}
@@ -552,7 +553,6 @@ fn layout_in_flow_replaced_block_level<'a>(
border,
margin,
block_margins_collapsed_with_children,
- None, // hoisted_fragment_id
)
}
diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs
index 0b93701b01b..adbcb26d4c9 100644
--- a/components/layout_2020/flow/root.rs
+++ b/components/layout_2020/flow/root.rs
@@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::display_list::stacking_context::{
ContainingBlock, ContainingBlockInfo, StackingContext, StackingContextBuildMode,
@@ -37,7 +38,7 @@ pub struct BoxTreeRoot(BlockFormattingContext);
#[derive(Serialize)]
pub struct FragmentTreeRoot {
/// The children of the root of the fragment tree.
- children: Vec<Fragment>,
+ children: Vec<ArcRefCell<Fragment>>,
/// The scrollable overflow of the root of the fragment tree.
scrollable_overflow: PhysicalRect<Length>,
@@ -49,7 +50,7 @@ pub struct FragmentTreeRoot {
impl BoxTreeRoot {
pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self
where
- Node: 'dom + Copy + LayoutNode + Send + Sync,
+ Node: 'dom + Copy + LayoutNode<'dom> + Send + Sync,
{
let (contains_floats, boxes) = construct_for_root_element(&context, root_element);
Self(BlockFormattingContext {
@@ -62,7 +63,7 @@ impl BoxTreeRoot {
fn construct_for_root_element<'dom>(
context: &LayoutContext,
root_element: impl NodeExt<'dom>,
-) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
+) -> (ContainsFloats, Vec<ArcRefCell<BlockLevelBox>>) {
let style = root_element.style(context);
let replaced = ReplacedContent::for_element(root_element);
let box_style = style.get_box();
@@ -83,27 +84,30 @@ fn construct_for_root_element<'dom>(
if box_style.position.is_absolutely_positioned() {
(
ContainsFloats::No,
- vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
- AbsolutelyPositionedBox::construct(
- context,
- root_element,
- style,
- display_inside,
- contents,
- ),
- ))],
+ vec![ArcRefCell::new(
+ BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
+ AbsolutelyPositionedBox::construct(
+ context,
+ root_element,
+ style,
+ display_inside,
+ contents,
+ ),
+ )),
+ )],
)
} else if box_style.float.is_floating() {
(
ContainsFloats::Yes,
- vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(
+ vec![ArcRefCell::new(BlockLevelBox::OutOfFlowFloatBox(
FloatBox::construct(context, root_element, style, display_inside, contents),
))],
)
} else {
+ let propagated_text_decoration_line = style.clone_text_decoration_line();
(
ContainsFloats::No,
- vec![Arc::new(BlockLevelBox::Independent(
+ vec![ArcRefCell::new(BlockLevelBox::Independent(
IndependentFormattingContext::construct(
context,
root_element,
@@ -111,6 +115,7 @@ fn construct_for_root_element<'dom>(
display_inside,
contents,
ContentSizesRequest::None,
+ propagated_text_decoration_line,
),
))],
)
@@ -142,44 +147,47 @@ impl BoxTreeRoot {
let dummy_tree_rank = 0;
let mut positioning_context =
PositioningContext::new_for_containing_block_for_all_descendants();
- let mut independent_layout = self.0.layout(
+ let independent_layout = self.0.layout(
layout_context,
&mut positioning_context,
&(&initial_containing_block).into(),
dummy_tree_rank,
);
+ let mut children = independent_layout
+ .fragments
+ .into_iter()
+ .map(|fragment| ArcRefCell::new(fragment))
+ .collect();
positioning_context.layout_initial_containing_block_children(
layout_context,
&initial_containing_block,
- &mut independent_layout.fragments,
+ &mut children,
);
- let scrollable_overflow =
- independent_layout
- .fragments
- .iter()
- .fold(PhysicalRect::zero(), |acc, child| {
- let child_overflow = child.scrollable_overflow();
+ let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| {
+ let child_overflow = child
+ .borrow()
+ .scrollable_overflow(&physical_containing_block);
- // https://drafts.csswg.org/css-overflow/#scrolling-direction
- // We want to clip scrollable overflow on box-start and inline-start
- // sides of the scroll container.
- //
- // FIXME(mrobinson, bug 25564): This should take into account writing
- // mode.
- let child_overflow = PhysicalRect::new(
- euclid::Point2D::zero(),
- euclid::Size2D::new(
- child_overflow.size.width + child_overflow.origin.x,
- child_overflow.size.height + child_overflow.origin.y,
- ),
- );
- acc.union(&child_overflow)
- });
+ // https://drafts.csswg.org/css-overflow/#scrolling-direction
+ // We want to clip scrollable overflow on box-start and inline-start
+ // sides of the scroll container.
+ //
+ // FIXME(mrobinson, bug 25564): This should take into account writing
+ // mode.
+ let child_overflow = PhysicalRect::new(
+ euclid::Point2D::zero(),
+ euclid::Size2D::new(
+ child_overflow.size.width + child_overflow.origin.x,
+ child_overflow.size.height + child_overflow.origin.y,
+ ),
+ );
+ acc.union(&child_overflow)
+ });
FragmentTreeRoot {
- children: independent_layout.fragments,
+ children,
scrollable_overflow,
initial_containing_block: physical_containing_block,
}
@@ -197,12 +205,12 @@ impl FragmentTreeRoot {
containing_block_for_all_descendants: ContainingBlock::new(
&self.initial_containing_block,
stacking_context_builder.current_space_and_clip,
- &self.children,
),
};
for fragment in &self.children {
- fragment.build_stacking_context_tree(
+ fragment.borrow().build_stacking_context_tree(
+ fragment,
&mut stacking_context_builder,
&containing_block_info,
&mut stacking_context,
@@ -218,7 +226,7 @@ impl FragmentTreeRoot {
pub fn print(&self) {
let mut print_tree = PrintTree::new("Fragment Tree".to_string());
for fragment in &self.children {
- fragment.print(&mut print_tree);
+ fragment.borrow().print(&mut print_tree);
}
}
@@ -233,49 +241,11 @@ impl FragmentTreeRoot {
&self,
mut process_func: impl FnMut(&Fragment, &PhysicalRect<Length>) -> Option<T>,
) -> Option<T> {
- fn recur<T>(
- fragments: &[Fragment],
- containing_block: &PhysicalRect<Length>,
- process_func: &mut impl FnMut(&Fragment, &PhysicalRect<Length>) -> Option<T>,
- ) -> Option<T> {
- for fragment in fragments {
- if let Some(result) = process_func(fragment, containing_block) {
- return Some(result);
- }
-
- match fragment {
- Fragment::Box(fragment) => {
- let new_containing_block = fragment
- .content_rect
- .to_physical(fragment.style.writing_mode, containing_block)
- .translate(containing_block.origin.to_vector());
- if let Some(result) =
- recur(&fragment.children, &new_containing_block, process_func)
- {
- return Some(result);
- }
- },
- Fragment::Anonymous(fragment) => {
- let new_containing_block = fragment
- .rect
- .to_physical(fragment.mode, containing_block)
- .translate(containing_block.origin.to_vector());
- if let Some(result) =
- recur(&fragment.children, &new_containing_block, process_func)
- {
- return Some(result);
- }
- },
- _ => {},
- }
- }
- None
- }
- recur(
- &self.children,
- &self.initial_containing_block,
- &mut process_func,
- )
+ self.children.iter().find_map(|child| {
+ child
+ .borrow()
+ .find(&self.initial_containing_block, &mut process_func)
+ })
}
pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect<Au> {