mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Auto merge of #26755 - servo:flexbox, r=nox
Add Layout 2020 box tree support for Flexbox, behind a pref CC https://github.com/servo/servo/issues/26639 Layout support will come in future PRs. This one generates a zero-size fragment with no content.
This commit is contained in:
commit
3d6fed85ff
13 changed files with 395 additions and 45 deletions
|
@ -454,6 +454,9 @@ mod gen {
|
|||
columns: {
|
||||
enabled: bool,
|
||||
},
|
||||
flexbox: {
|
||||
enabled: bool,
|
||||
},
|
||||
#[serde(default = "default_layout_threads")]
|
||||
threads: i64,
|
||||
viewport: {
|
||||
|
|
|
@ -64,14 +64,14 @@ where
|
|||
&mut self,
|
||||
node: Node,
|
||||
text: Cow<'dom, str>,
|
||||
parent_style: &ServoArc<ComputedValues>,
|
||||
parent_style: ServoArc<ComputedValues>,
|
||||
);
|
||||
|
||||
/// Or pseudo-element
|
||||
fn handle_element(
|
||||
&mut self,
|
||||
node: Node,
|
||||
style: &ServoArc<ComputedValues>,
|
||||
style: ServoArc<ComputedValues>,
|
||||
display: DisplayGeneratingBox,
|
||||
contents: Contents,
|
||||
box_slot: BoxSlot<'dom>,
|
||||
|
@ -89,7 +89,7 @@ fn traverse_children_of<'dom, Node>(
|
|||
|
||||
for child in iter_child_nodes(parent_element) {
|
||||
if let Some(contents) = child.as_text() {
|
||||
handler.handle_text(child, contents, &child.style(context));
|
||||
handler.handle_text(child, contents, child.style(context));
|
||||
} else if child.is_element() {
|
||||
traverse_element(child, context, handler);
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ fn traverse_element<'dom, Node>(
|
|||
Display::GeneratingBox(display) => {
|
||||
let contents = replaced.map_or(Contents::OfElement, Contents::Replaced);
|
||||
let box_slot = element.element_box_slot();
|
||||
handler.handle_element(element, &style, display, contents, box_slot);
|
||||
handler.handle_element(element, style, display, contents, box_slot);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ fn traverse_pseudo_element<'dom, Node>(
|
|||
let items = generate_pseudo_element_content(&style, element, context);
|
||||
let box_slot = element.pseudo_element_box_slot(which);
|
||||
let contents = Contents::OfPseudoElement(items);
|
||||
handler.handle_element(element, &style, display, contents, box_slot);
|
||||
handler.handle_element(element, style, display, contents, box_slot);
|
||||
},
|
||||
}
|
||||
} else {
|
||||
|
@ -169,7 +169,7 @@ fn traverse_pseudo_element_contents<'dom, Node>(
|
|||
for item in items {
|
||||
match item {
|
||||
PseudoElementContentItem::Text(text) => {
|
||||
handler.handle_text(node, text.into(), pseudo_element_style)
|
||||
handler.handle_text(node, text.into(), pseudo_element_style.clone())
|
||||
},
|
||||
PseudoElementContentItem::Replaced(contents) => {
|
||||
let item_style = anonymous_style.get_or_insert_with(|| {
|
||||
|
@ -193,7 +193,7 @@ fn traverse_pseudo_element_contents<'dom, Node>(
|
|||
);
|
||||
handler.handle_element(
|
||||
node,
|
||||
item_style,
|
||||
item_style.clone(),
|
||||
display_inline,
|
||||
Contents::Replaced(contents),
|
||||
// We don’t keep pointers to boxes generated by contents of pseudo-elements
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::cell::ArcRefCell;
|
||||
use crate::flexbox::FlexLevelBox;
|
||||
use crate::flow::inline::InlineLevelBox;
|
||||
use crate::flow::BlockLevelBox;
|
||||
|
||||
|
@ -17,4 +18,5 @@ pub(super) enum LayoutBox {
|
|||
DisplayContents,
|
||||
BlockLevel(ArcRefCell<BlockLevelBox>),
|
||||
InlineLevel(ArcRefCell<InlineLevelBox>),
|
||||
FlexLevel(ArcRefCell<FlexLevelBox>),
|
||||
}
|
||||
|
|
261
components/layout_2020/flexbox.rs
Normal file
261
components/layout_2020/flexbox.rs
Normal file
|
@ -0,0 +1,261 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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;
|
||||
use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout};
|
||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
||||
use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest};
|
||||
use crate::style_ext::DisplayGeneratingBox;
|
||||
use crate::ContainingBlock;
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
use servo_arc::Arc;
|
||||
use std::borrow::Cow;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::Length;
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
use style::Zero;
|
||||
|
||||
// FIXME: `min-width: auto` is not zero: https://drafts.csswg.org/css-flexbox/#min-size-auto
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub(crate) struct FlexContainer {
|
||||
children: Vec<ArcRefCell<FlexLevelBox>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub(crate) enum FlexLevelBox {
|
||||
FlexItem(IndependentFormattingContext),
|
||||
OutOfFlowAbsolutelyPositionedBox(Arc<AbsolutelyPositionedBox>),
|
||||
}
|
||||
|
||||
impl FlexContainer {
|
||||
pub fn construct<'dom>(
|
||||
context: &LayoutContext,
|
||||
node: impl NodeExt<'dom>,
|
||||
style: &Arc<ComputedValues>,
|
||||
contents: NonReplacedContents,
|
||||
content_sizes: ContentSizesRequest,
|
||||
propagated_text_decoration_line: TextDecorationLine,
|
||||
) -> (Self, BoxContentSizes) {
|
||||
let text_decoration_line =
|
||||
propagated_text_decoration_line | style.clone_text_decoration_line();
|
||||
let mut builder = FlexContainerBuilder {
|
||||
context,
|
||||
node,
|
||||
style,
|
||||
text_decoration_line,
|
||||
contiguous_text_runs: Vec::new(),
|
||||
jobs: Vec::new(),
|
||||
has_text_runs: false,
|
||||
};
|
||||
contents.traverse(context, node, style, &mut builder);
|
||||
let content_sizes = content_sizes.compute(|| {
|
||||
// FIXME
|
||||
ContentSizes::zero()
|
||||
});
|
||||
(builder.finish(), content_sizes)
|
||||
}
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/css-flexbox/#flex-items
|
||||
struct FlexContainerBuilder<'a, 'dom, Node> {
|
||||
context: &'a LayoutContext<'a>,
|
||||
node: Node,
|
||||
style: &'a Arc<ComputedValues>,
|
||||
text_decoration_line: TextDecorationLine,
|
||||
contiguous_text_runs: Vec<TextRun<'dom, Node>>,
|
||||
/// To be run in parallel with rayon in `finish`
|
||||
jobs: Vec<FlexLevelJob<'dom, Node>>,
|
||||
has_text_runs: bool,
|
||||
}
|
||||
|
||||
enum FlexLevelJob<'dom, Node> {
|
||||
/// Or pseudo-element
|
||||
Element {
|
||||
node: Node,
|
||||
style: Arc<ComputedValues>,
|
||||
display: DisplayGeneratingBox,
|
||||
contents: Contents,
|
||||
box_slot: BoxSlot<'dom>,
|
||||
},
|
||||
TextRuns(Vec<TextRun<'dom, Node>>),
|
||||
}
|
||||
|
||||
struct TextRun<'dom, Node> {
|
||||
node: Node,
|
||||
text: Cow<'dom, str>,
|
||||
parent_style: Arc<ComputedValues>,
|
||||
}
|
||||
|
||||
impl<'a, 'dom, Node: 'dom> TraversalHandler<'dom, Node> for FlexContainerBuilder<'a, 'dom, Node>
|
||||
where
|
||||
Node: NodeExt<'dom>,
|
||||
{
|
||||
fn handle_text(&mut self, node: Node, text: Cow<'dom, str>, parent_style: Arc<ComputedValues>) {
|
||||
self.contiguous_text_runs.push(TextRun {
|
||||
node,
|
||||
text,
|
||||
parent_style,
|
||||
})
|
||||
}
|
||||
|
||||
/// Or pseudo-element
|
||||
fn handle_element(
|
||||
&mut self,
|
||||
node: Node,
|
||||
style: Arc<ComputedValues>,
|
||||
display: DisplayGeneratingBox,
|
||||
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();
|
||||
|
||||
self.jobs.push(FlexLevelJob::Element {
|
||||
node,
|
||||
style,
|
||||
display,
|
||||
contents,
|
||||
box_slot,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/css-text/#white-space
|
||||
fn is_only_document_white_space<Node>(run: &TextRun<'_, Node>) -> bool {
|
||||
// FIXME: is this the right definition? See
|
||||
// https://github.com/w3c/csswg-drafts/issues/5146
|
||||
// https://github.com/w3c/csswg-drafts/issues/5147
|
||||
run.text
|
||||
.bytes()
|
||||
.all(|byte| matches!(byte, b' ' | b'\n' | b'\t'))
|
||||
}
|
||||
|
||||
impl<'a, 'dom, Node: 'dom> FlexContainerBuilder<'a, 'dom, Node>
|
||||
where
|
||||
Node: NodeExt<'dom>,
|
||||
{
|
||||
fn wrap_any_text_in_anonymous_block_container(&mut self) {
|
||||
let runs = std::mem::take(&mut self.contiguous_text_runs);
|
||||
if runs.iter().all(is_only_document_white_space) {
|
||||
// There is no text run, or they all only contain document white space characters
|
||||
} else {
|
||||
self.jobs.push(FlexLevelJob::TextRuns(runs));
|
||||
self.has_text_runs = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn finish(mut self) -> FlexContainer {
|
||||
self.wrap_any_text_in_anonymous_block_container();
|
||||
|
||||
let anonymous_style = if self.has_text_runs {
|
||||
Some(
|
||||
self.context
|
||||
.shared_context()
|
||||
.stylist
|
||||
.style_for_anonymous::<Node::ConcreteElement>(
|
||||
&self.context.shared_context().guards,
|
||||
&style::selector_parser::PseudoElement::ServoText,
|
||||
self.style,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut children = std::mem::take(&mut self.jobs)
|
||||
.into_par_iter()
|
||||
.map(|job| match job {
|
||||
FlexLevelJob::TextRuns(runs) => ArcRefCell::new(FlexLevelBox::FlexItem(
|
||||
IndependentFormattingContext::construct_for_text_runs(
|
||||
self.context,
|
||||
self.node,
|
||||
anonymous_style.clone().unwrap(),
|
||||
runs.into_iter().map(|run| crate::flow::inline::TextRun {
|
||||
tag: run.node.as_opaque(),
|
||||
text: run.text.into(),
|
||||
parent_style: run.parent_style,
|
||||
}),
|
||||
ContentSizesRequest::None, // FIXME: request sizes when we start using them
|
||||
self.text_decoration_line,
|
||||
),
|
||||
)),
|
||||
FlexLevelJob::Element {
|
||||
node,
|
||||
style,
|
||||
display,
|
||||
contents,
|
||||
box_slot,
|
||||
} => {
|
||||
let display_inside = match display {
|
||||
DisplayGeneratingBox::OutsideInside { inside, .. } => inside,
|
||||
};
|
||||
let box_ = if style.get_box().position.is_absolutely_positioned() {
|
||||
// https://drafts.csswg.org/css-flexbox/#abspos-items
|
||||
ArcRefCell::new(FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
|
||||
AbsolutelyPositionedBox::construct(
|
||||
self.context,
|
||||
node,
|
||||
style.clone(),
|
||||
display_inside,
|
||||
contents,
|
||||
),
|
||||
)))
|
||||
} else {
|
||||
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,
|
||||
),
|
||||
))
|
||||
};
|
||||
box_slot.set(LayoutBox::FlexLevel(box_.clone()));
|
||||
box_
|
||||
},
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// https://drafts.csswg.org/css-flexbox/#order-modified-document-order
|
||||
children.sort_by_key(|child| match &*child.borrow() {
|
||||
FlexLevelBox::FlexItem(item) => item.style.clone_order(),
|
||||
|
||||
// “Absolutely-positioned children of a flex container are treated
|
||||
// as having order: 0 for the purpose of determining their painting order
|
||||
// relative to flex items.”
|
||||
FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(_) => 0,
|
||||
});
|
||||
|
||||
FlexContainer { children }
|
||||
}
|
||||
}
|
||||
|
||||
impl FlexContainer {
|
||||
pub(crate) fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
positioning_context: &mut PositioningContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
) -> IndependentLayout {
|
||||
// FIXME
|
||||
let _ = layout_context;
|
||||
let _ = positioning_context;
|
||||
let _ = containing_block;
|
||||
let _ = tree_rank;
|
||||
IndependentLayout {
|
||||
fragments: Vec::new(),
|
||||
content_block_size: Length::zero(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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> {
|
||||
|
@ -249,7 +273,7 @@ where
|
|||
fn handle_element(
|
||||
&mut self,
|
||||
node: Node,
|
||||
style: &Arc<ComputedValues>,
|
||||
style: Arc<ComputedValues>,
|
||||
display: DisplayGeneratingBox,
|
||||
contents: Contents,
|
||||
box_slot: BoxSlot<'dom>,
|
||||
|
@ -265,22 +289,12 @@ where
|
|||
// https://drafts.csswg.org/css2/visuren.html#dis-pos-flo
|
||||
if box_style.position.is_absolutely_positioned() {
|
||||
self.handle_absolutely_positioned_element(
|
||||
node,
|
||||
style.clone(),
|
||||
inside,
|
||||
contents,
|
||||
box_slot,
|
||||
node, style, inside, contents, box_slot,
|
||||
)
|
||||
} else if box_style.float.is_floating() {
|
||||
self.handle_float_element(node, style.clone(), inside, contents, box_slot)
|
||||
self.handle_float_element(node, style, inside, contents, box_slot)
|
||||
} else {
|
||||
self.handle_block_level_element(
|
||||
node,
|
||||
style.clone(),
|
||||
inside,
|
||||
contents,
|
||||
box_slot,
|
||||
)
|
||||
self.handle_block_level_element(node, style, inside, contents, box_slot)
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -291,7 +305,7 @@ where
|
|||
&mut self,
|
||||
node: Node,
|
||||
input: Cow<'dom, str>,
|
||||
parent_style: &Arc<ComputedValues>,
|
||||
parent_style: Arc<ComputedValues>,
|
||||
) {
|
||||
let (leading_whitespace, mut input) = self.handle_leading_whitespace(&input);
|
||||
if leading_whitespace || !input.is_empty() {
|
||||
|
@ -341,7 +355,6 @@ where
|
|||
}
|
||||
|
||||
if let Some(text) = new_text_run_contents {
|
||||
let parent_style = parent_style.clone();
|
||||
inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun {
|
||||
tag: node.as_opaque(),
|
||||
parent_style,
|
||||
|
@ -418,7 +431,7 @@ where
|
|||
fn handle_inline_level_element(
|
||||
&mut self,
|
||||
node: Node,
|
||||
style: &Arc<ComputedValues>,
|
||||
style: Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents,
|
||||
) -> ArcRefCell<InlineLevelBox> {
|
||||
|
@ -449,14 +462,15 @@ where
|
|||
inline_box.last_fragment = true;
|
||||
ArcRefCell::new(InlineLevelBox::InlineBox(inline_box))
|
||||
} else {
|
||||
let content_sizes = ContentSizesRequest::inline_if(!style.inline_size_is_length());
|
||||
ArcRefCell::new(InlineLevelBox::Atomic(
|
||||
IndependentFormattingContext::construct(
|
||||
self.context,
|
||||
node,
|
||||
style.clone(),
|
||||
style,
|
||||
display_inside,
|
||||
contents,
|
||||
ContentSizesRequest::inline_if(!style.inline_size_is_length()),
|
||||
content_sizes,
|
||||
// Text decorations are not propagated to atomic inline-level descendants.
|
||||
TextDecorationLine::NONE,
|
||||
),
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::display_list::stacking_context::{
|
|||
};
|
||||
use crate::dom_traversal::{iter_child_nodes, Contents, NodeExt};
|
||||
use crate::element_data::LayoutBox;
|
||||
use crate::flexbox::FlexLevelBox;
|
||||
use crate::flow::construct::ContainsFloats;
|
||||
use crate::flow::float::FloatBox;
|
||||
use crate::flow::inline::InlineLevelBox;
|
||||
|
@ -119,6 +120,7 @@ impl BoxTree {
|
|||
enum UpdatePoint {
|
||||
AbsolutelyPositionedBlockLevelBox(ArcRefCell<BlockLevelBox>),
|
||||
AbsolutelyPositionedInlineLevelBox(ArcRefCell<InlineLevelBox>),
|
||||
AbsolutelyPositionedFlexLevelBox(ArcRefCell<FlexLevelBox>),
|
||||
}
|
||||
|
||||
fn update_point<'dom, Node>(
|
||||
|
@ -188,6 +190,14 @@ impl BoxTree {
|
|||
},
|
||||
_ => return None,
|
||||
},
|
||||
LayoutBox::FlexLevel(flex_level_box) => match &*flex_level_box.borrow() {
|
||||
FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(_)
|
||||
if box_style.position.is_absolutely_positioned() =>
|
||||
{
|
||||
UpdatePoint::AbsolutelyPositionedFlexLevelBox(flex_level_box.clone())
|
||||
},
|
||||
_ => return None,
|
||||
},
|
||||
};
|
||||
Some((primary_style.clone(), display_inside, update_point))
|
||||
}
|
||||
|
@ -217,6 +227,12 @@ impl BoxTree {
|
|||
out_of_flow_absolutely_positioned_box,
|
||||
);
|
||||
},
|
||||
UpdatePoint::AbsolutelyPositionedFlexLevelBox(flex_level_box) => {
|
||||
*flex_level_box.borrow_mut() =
|
||||
FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(
|
||||
out_of_flow_absolutely_positioned_box,
|
||||
);
|
||||
},
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use crate::context::LayoutContext;
|
||||
use crate::dom_traversal::{Contents, NodeExt};
|
||||
use crate::flexbox::FlexContainer;
|
||||
use crate::flow::BlockFormattingContext;
|
||||
use crate::fragments::Fragment;
|
||||
use crate::positioned::PositioningContext;
|
||||
|
@ -43,6 +44,7 @@ pub(crate) struct IndependentLayout {
|
|||
#[derive(Debug, Serialize)]
|
||||
enum IndependentFormattingContextContents {
|
||||
Flow(BlockFormattingContext),
|
||||
Flex(FlexContainer),
|
||||
|
||||
// Not called FC in specs, but behaves close enough
|
||||
Replaced(ReplacedContent),
|
||||
|
@ -53,6 +55,7 @@ pub(crate) struct NonReplacedIFC<'a>(NonReplacedIFCKind<'a>);
|
|||
|
||||
enum NonReplacedIFCKind<'a> {
|
||||
Flow(&'a BlockFormattingContext),
|
||||
Flex(&'a FlexContainer),
|
||||
}
|
||||
|
||||
impl IndependentFormattingContext {
|
||||
|
@ -83,6 +86,22 @@ impl IndependentFormattingContext {
|
|||
contents: IndependentFormattingContextContents::Flow(bfc),
|
||||
}
|
||||
},
|
||||
DisplayInside::Flex => {
|
||||
let (fc, content_sizes) = FlexContainer::construct(
|
||||
context,
|
||||
node,
|
||||
&style,
|
||||
non_replaced,
|
||||
content_sizes,
|
||||
propagated_text_decoration_line,
|
||||
);
|
||||
Self {
|
||||
tag: node.as_opaque(),
|
||||
style,
|
||||
content_sizes,
|
||||
contents: IndependentFormattingContextContents::Flex(fc),
|
||||
}
|
||||
},
|
||||
},
|
||||
Err(replaced) => {
|
||||
let content_sizes = content_sizes.compute(|| replaced.inline_content_sizes(&style));
|
||||
|
@ -96,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;
|
||||
|
@ -103,6 +144,7 @@ impl IndependentFormattingContext {
|
|||
match &self.contents {
|
||||
Contents::Replaced(r) => Ok(r),
|
||||
Contents::Flow(f) => Err(NR(Kind::Flow(f))),
|
||||
Contents::Flex(f) => Err(NR(Kind::Flex(f))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,6 +164,12 @@ impl NonReplacedIFC<'_> {
|
|||
containing_block,
|
||||
tree_rank,
|
||||
),
|
||||
NonReplacedIFCKind::Flex(fc) => fc.layout(
|
||||
layout_context,
|
||||
positioning_context,
|
||||
containing_block,
|
||||
tree_rank,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ pub mod data;
|
|||
pub mod display_list;
|
||||
mod dom_traversal;
|
||||
pub mod element_data;
|
||||
mod flexbox;
|
||||
mod flow;
|
||||
mod formatting_contexts;
|
||||
mod fragments;
|
||||
|
|
|
@ -48,6 +48,7 @@ pub(crate) enum DisplayOutside {
|
|||
pub(crate) enum DisplayInside {
|
||||
Flow,
|
||||
FlowRoot,
|
||||
Flex,
|
||||
}
|
||||
|
||||
/// Percentages resolved but not `auto` margins
|
||||
|
@ -394,6 +395,7 @@ impl From<stylo::Display> for Display {
|
|||
let inside = match packed.inside() {
|
||||
stylo::DisplayInside::Flow => DisplayInside::Flow,
|
||||
stylo::DisplayInside::FlowRoot => DisplayInside::FlowRoot,
|
||||
stylo::DisplayInside::Flex => DisplayInside::Flex,
|
||||
|
||||
// These should not be values of DisplayInside, but oh well
|
||||
stylo::DisplayInside::None => return Display::None,
|
||||
|
|
|
@ -266,7 +266,8 @@ ${helpers.predefined_type(
|
|||
"order",
|
||||
"Integer",
|
||||
"0",
|
||||
engines="gecko servo-2013",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
servo_2020_pref="layout.flexbox.enabled",
|
||||
extra_prefixes="webkit",
|
||||
animation_value_type="ComputedValue",
|
||||
spec="https://drafts.csswg.org/css-flexbox/#order-property",
|
||||
|
|
|
@ -34,6 +34,17 @@ fn moz_box_display_values_enabled(context: &ParserContext) -> bool {
|
|||
static_prefs::pref!("layout.css.xul-box-display-values.content.enabled")
|
||||
}
|
||||
|
||||
fn flexbox_enabled() -> bool {
|
||||
if cfg!(feature = "servo-layout-2020") {
|
||||
servo_config::prefs::pref_map()
|
||||
.get("layout.flexbox.enabled")
|
||||
.as_bool()
|
||||
.unwrap_or(false)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines an element’s display type, which consists of
|
||||
/// the two basic qualities of how an element generates boxes
|
||||
/// <https://drafts.csswg.org/css-display/#propdef-display>
|
||||
|
@ -63,7 +74,6 @@ pub enum DisplayInside {
|
|||
Contents,
|
||||
Flow,
|
||||
FlowRoot,
|
||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||
Flex,
|
||||
#[cfg(feature = "gecko")]
|
||||
Grid,
|
||||
|
@ -146,9 +156,7 @@ impl Display {
|
|||
pub const Block: Self = Self::new(DisplayOutside::Block, DisplayInside::Flow);
|
||||
#[cfg(feature = "gecko")]
|
||||
pub const FlowRoot: Self = Self::new(DisplayOutside::Block, DisplayInside::FlowRoot);
|
||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||
pub const Flex: Self = Self::new(DisplayOutside::Block, DisplayInside::Flex);
|
||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||
pub const InlineFlex: Self = Self::new(DisplayOutside::Inline, DisplayInside::Flex);
|
||||
#[cfg(feature = "gecko")]
|
||||
pub const Grid: Self = Self::new(DisplayOutside::Block, DisplayInside::Grid);
|
||||
|
@ -317,9 +325,9 @@ impl Display {
|
|||
#[inline]
|
||||
pub fn is_atomic_inline_level(&self) -> bool {
|
||||
match *self {
|
||||
Display::InlineBlock => true,
|
||||
Display::InlineBlock | Display::InlineFlex => true,
|
||||
#[cfg(any(feature = "servo-layout-2013"))]
|
||||
Display::InlineFlex | Display::InlineTable => true,
|
||||
Display::InlineTable => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -330,7 +338,6 @@ impl Display {
|
|||
/// This is used to implement various style fixups.
|
||||
pub fn is_item_container(&self) -> bool {
|
||||
match self.inside() {
|
||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||
DisplayInside::Flex => true,
|
||||
#[cfg(feature = "gecko")]
|
||||
DisplayInside::Grid => true,
|
||||
|
@ -432,12 +439,9 @@ impl ToCss for Display {
|
|||
_ => match (outside, inside) {
|
||||
#[cfg(feature = "gecko")]
|
||||
(DisplayOutside::Inline, DisplayInside::Grid) => dest.write_str("inline-grid"),
|
||||
(DisplayOutside::Inline, DisplayInside::Flex) => dest.write_str("inline-flex"),
|
||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||
(DisplayOutside::Inline, DisplayInside::Flex) |
|
||||
(DisplayOutside::Inline, DisplayInside::Table) => {
|
||||
dest.write_str("inline-")?;
|
||||
inside.to_css(dest)
|
||||
},
|
||||
(DisplayOutside::Inline, DisplayInside::Table) => dest.write_str("inline-table"),
|
||||
#[cfg(feature = "gecko")]
|
||||
(DisplayOutside::Block, DisplayInside::Ruby) => dest.write_str("block ruby"),
|
||||
(_, inside) => {
|
||||
|
@ -467,12 +471,11 @@ fn parse_display_inside<'i, 't>(
|
|||
) -> Result<DisplayInside, ParseError<'i>> {
|
||||
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||
"flow" => DisplayInside::Flow,
|
||||
"flex" if flexbox_enabled() => DisplayInside::Flex,
|
||||
#[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
|
||||
"flow-root" => DisplayInside::FlowRoot,
|
||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||
"table" => DisplayInside::Table,
|
||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||
"flex" => DisplayInside::Flex,
|
||||
#[cfg(feature = "gecko")]
|
||||
"grid" => DisplayInside::Grid,
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -575,10 +578,8 @@ impl Parse for Display {
|
|||
"inline-block" => Display::InlineBlock,
|
||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||
"inline-table" => Display::InlineTable,
|
||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||
"-webkit-flex" => Display::Flex,
|
||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||
"inline-flex" | "-webkit-inline-flex" => Display::InlineFlex,
|
||||
"-webkit-flex" if flexbox_enabled() => Display::Flex,
|
||||
"inline-flex" | "-webkit-inline-flex" if flexbox_enabled() => Display::InlineFlex,
|
||||
#[cfg(feature = "gecko")]
|
||||
"inline-grid" => Display::InlineGrid,
|
||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
"js.werror.enabled": false,
|
||||
"layout.animations.test.enabled": false,
|
||||
"layout.columns.enabled": false,
|
||||
"layout.flexbox.enabled": false,
|
||||
"layout.threads": 3,
|
||||
"layout.viewport.enabled": false,
|
||||
"layout.writing-mode.enabled": false,
|
||||
|
|
|
@ -1 +1 @@
|
|||
prefs: ["layout.columns.enabled:true"]
|
||||
prefs: ["layout.columns.enabled:true", "layout.flexbox.enabled:true"]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue