aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Sapin <simon.sapin@exyr.org>2020-06-02 18:16:35 +0200
committerSimon Sapin <simon.sapin@exyr.org>2020-06-04 13:19:53 +0200
commit67d8aa84d2e63503a9d5c250f0eb1eb659f84619 (patch)
tree386a132daae74fbb3a3a29e715bbd48d3932ddd0
parentec548e849ca328ccc18404313369dbffcf0a17b9 (diff)
downloadservo-67d8aa84d2e63503a9d5c250f0eb1eb659f84619.tar.gz
servo-67d8aa84d2e63503a9d5c250f0eb1eb659f84619.zip
Anonymous flex item for text directly in a flex container
-rw-r--r--components/layout_2020/flexbox.rs114
-rw-r--r--components/layout_2020/flow/construct.rs24
-rw-r--r--components/layout_2020/formatting_contexts.rs22
3 files changed, 139 insertions, 21 deletions
diff --git a/components/layout_2020/flexbox.rs b/components/layout_2020/flexbox.rs
index 1ab3e015aff..154c9ab3071 100644
--- a/components/layout_2020/flexbox.rs
+++ b/components/layout_2020/flexbox.rs
@@ -6,6 +6,7 @@ use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::dom_traversal::{BoxSlot, Contents, NodeExt, NonReplacedContents, TraversalHandler};
use crate::element_data::LayoutBox;
+use crate::flow::inline::TextRun;
use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout};
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest};
@@ -44,27 +45,34 @@ impl FlexContainer {
propagated_text_decoration_line | style.clone_text_decoration_line();
let mut builder = FlexContainerBuilder {
context,
+ node,
+ style,
+ anonymous_style: None,
text_decoration_line,
- flex_container: Self {
- children: Vec::new(),
- },
+ contiguous_text_runs: Vec::new(),
+ children: Vec::new(),
};
contents.traverse(context, node, style, &mut builder);
let content_sizes = content_sizes.compute(|| {
// FIXME
ContentSizes::zero()
});
- (builder.flex_container, content_sizes)
+ (builder.finish(), content_sizes)
}
}
-struct FlexContainerBuilder<'context> {
- context: &'context LayoutContext<'context>,
+/// https://drafts.csswg.org/css-flexbox/#flex-items
+struct FlexContainerBuilder<'a, Node> {
+ context: &'a LayoutContext<'a>,
+ node: Node,
+ style: &'a Arc<ComputedValues>,
+ anonymous_style: Option<Arc<ComputedValues>>,
text_decoration_line: TextDecorationLine,
- flex_container: FlexContainer,
+ contiguous_text_runs: Vec<TextRun>,
+ children: Vec<ArcRefCell<FlexLevelBox>>,
}
-impl<'context, 'dom, Node: 'dom> TraversalHandler<'dom, Node> for FlexContainerBuilder<'context>
+impl<'a, 'dom, Node: 'dom> TraversalHandler<'dom, Node> for FlexContainerBuilder<'a, Node>
where
Node: NodeExt<'dom>,
{
@@ -74,10 +82,11 @@ where
text: Cow<'dom, str>,
parent_style: &Arc<ComputedValues>,
) {
- // FIXME
- let _ = node;
- let _ = text;
- let _ = parent_style;
+ self.contiguous_text_runs.push(TextRun {
+ tag: node.as_opaque(),
+ parent_style: parent_style.clone(),
+ text: text.into(),
+ })
}
/// Or pseudo-element
@@ -89,6 +98,11 @@ where
contents: Contents,
box_slot: BoxSlot<'dom>,
) {
+ // FIXME: are text runs considered "contiguous" if they are only separated
+ // by an out-of-flow abspos element?
+ // (That is, are they wrapped in the same anonymous flex item, or each its own?)
+ self.wrap_any_text_in_anonymous_block_container();
+
let display_inside = match display {
DisplayGeneratingBox::OutsideInside { inside, .. } => inside,
};
@@ -104,18 +118,76 @@ where
),
)))
} else {
- ArcRefCell::new(FlexLevelBox::FlexItem(IndependentFormattingContext::construct(
+ ArcRefCell::new(FlexLevelBox::FlexItem(
+ IndependentFormattingContext::construct(
+ self.context,
+ node,
+ style.clone(),
+ display_inside,
+ contents,
+ ContentSizesRequest::None, // FIXME: request sizes when we start using them
+ self.text_decoration_line,
+ ),
+ ))
+ };
+ self.children.push(box_.clone());
+ box_slot.set(LayoutBox::FlexLevel(box_))
+ }
+}
+
+/// https://drafts.csswg.org/css-text/#white-space
+fn is_only_document_white_space(string: &str) -> bool {
+ // FIXME: is this the right definition? See
+ // https://github.com/w3c/csswg-drafts/issues/5146
+ // https://github.com/w3c/csswg-drafts/issues/5147
+ string
+ .bytes()
+ .all(|byte| matches!(byte, b' ' | b'\n' | b'\t'))
+}
+
+impl<'a, 'dom, Node: 'dom> FlexContainerBuilder<'a, Node>
+where
+ Node: NodeExt<'dom>,
+{
+ fn wrap_any_text_in_anonymous_block_container(&mut self) {
+ if self
+ .contiguous_text_runs
+ .iter()
+ .all(|run| is_only_document_white_space(&run.text))
+ {
+ // There is no text run, or they all only contain document white space characters
+ self.contiguous_text_runs.clear();
+ return;
+ }
+ let context = self.context;
+ let style = self.style;
+ let anonymous_style = self.anonymous_style.get_or_insert_with(|| {
+ context
+ .shared_context()
+ .stylist
+ .style_for_anonymous::<Node::ConcreteElement>(
+ &context.shared_context().guards,
+ &style::selector_parser::PseudoElement::ServoText,
+ style,
+ )
+ });
+ self.children.push(ArcRefCell::new(FlexLevelBox::FlexItem(
+ IndependentFormattingContext::construct_for_text_runs(
self.context,
- node,
- style.clone(),
- display_inside,
- contents,
+ self.node,
+ anonymous_style.clone(),
+ self.contiguous_text_runs.drain(..),
ContentSizesRequest::None, // FIXME: request sizes when we start using them
self.text_decoration_line,
- )))
- };
- self.flex_container.children.push(box_.clone());
- box_slot.set(LayoutBox::FlexLevel(box_))
+ ),
+ )))
+ }
+
+ fn finish(mut self) -> FlexContainer {
+ self.wrap_any_text_in_anonymous_block_container();
+ FlexContainer {
+ children: self.children,
+ }
}
}
diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs
index 186a4b4d4ff..a0f6af39357 100644
--- a/components/layout_2020/flow/construct.rs
+++ b/components/layout_2020/flow/construct.rs
@@ -47,6 +47,30 @@ impl BlockFormattingContext {
};
(bfc, inline_content_sizes)
}
+
+ pub fn construct_for_text_runs<'dom>(
+ context: &LayoutContext,
+ runs: impl Iterator<Item = TextRun>,
+ content_sizes: ContentSizesRequest,
+ text_decoration_line: TextDecorationLine,
+ ) -> (Self, BoxContentSizes) {
+ // FIXME: do white space collapsing
+ let inline_level_boxes = runs
+ .map(|run| ArcRefCell::new(InlineLevelBox::TextRun(run)))
+ .collect();
+
+ let ifc = InlineFormattingContext {
+ inline_level_boxes,
+ text_decoration_line,
+ };
+ let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context));
+ let contents = BlockContainer::InlineFormattingContext(ifc);
+ let bfc = Self {
+ contents,
+ contains_floats: false,
+ };
+ (bfc, content_sizes)
+ }
}
struct BlockLevelJob<'dom, Node> {
diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs
index a94b9b374d1..a721b54ba0f 100644
--- a/components/layout_2020/formatting_contexts.rs
+++ b/components/layout_2020/formatting_contexts.rs
@@ -115,6 +115,28 @@ impl IndependentFormattingContext {
}
}
+ pub fn construct_for_text_runs<'dom>(
+ context: &LayoutContext,
+ node: impl NodeExt<'dom>,
+ style: Arc<ComputedValues>,
+ runs: impl Iterator<Item = crate::flow::inline::TextRun>,
+ content_sizes: ContentSizesRequest,
+ propagated_text_decoration_line: TextDecorationLine,
+ ) -> Self {
+ let (bfc, content_sizes) = BlockFormattingContext::construct_for_text_runs(
+ context,
+ runs,
+ content_sizes,
+ propagated_text_decoration_line,
+ );
+ Self {
+ tag: node.as_opaque(),
+ style,
+ content_sizes,
+ contents: IndependentFormattingContextContents::Flow(bfc),
+ }
+ }
+
pub fn as_replaced(&self) -> Result<&ReplacedContent, NonReplacedIFC> {
use self::IndependentFormattingContextContents as Contents;
use self::NonReplacedIFC as NR;