mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Anonymous flex item for text directly in a flex container
This commit is contained in:
parent
ec548e849c
commit
67d8aa84d2
3 changed files with 139 additions and 21 deletions
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue