aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout_2020')
-rw-r--r--components/layout_2020/Cargo.toml5
-rw-r--r--components/layout_2020/context.rs3
-rw-r--r--components/layout_2020/data.rs4
-rw-r--r--components/layout_2020/dom_traversal.rs388
-rw-r--r--components/layout_2020/element_data.rs8
-rw-r--r--components/layout_2020/flow/construct.rs352
-rw-r--r--components/layout_2020/flow/float.rs12
-rw-r--r--components/layout_2020/flow/inline.rs160
-rw-r--r--components/layout_2020/flow/mod.rs113
-rw-r--r--components/layout_2020/flow/root.rs227
-rw-r--r--components/layout_2020/fragments.rs15
-rw-r--r--components/layout_2020/geom.rs58
-rw-r--r--components/layout_2020/lib.rs148
-rw-r--r--components/layout_2020/positioned.rs89
-rw-r--r--components/layout_2020/primitives.rs28
-rw-r--r--components/layout_2020/replaced.rs13
-rw-r--r--components/layout_2020/style_ext.rs129
17 files changed, 1050 insertions, 702 deletions
diff --git a/components/layout_2020/Cargo.toml b/components/layout_2020/Cargo.toml
index 296d069c7e1..af6b53ace4b 100644
--- a/components/layout_2020/Cargo.toml
+++ b/components/layout_2020/Cargo.toml
@@ -14,6 +14,8 @@ doctest = false
[dependencies]
app_units = "0.7"
+atomic_refcell = "0.1"
+cssparser = "0.25"
euclid = "0.20"
fnv = "1.0"
gfx = {path = "../gfx"}
@@ -21,12 +23,15 @@ gfx_traits = {path = "../gfx_traits"}
ipc-channel = "0.12"
libc = "0.2"
malloc_size_of = { path = "../malloc_size_of" }
+matches = "0.1"
msg = {path = "../msg"}
range = {path = "../range"}
rayon = "1"
+rayon_croissant = "0.1.1"
script_layout_interface = {path = "../script_layout_interface"}
script_traits = {path = "../script_traits"}
serde = "1.0"
+servo_arc = { path = "../servo_arc" }
servo_url = {path = "../url"}
style = {path = "../style", features = ["servo", "servo-layout-2020"]}
style_traits = {path = "../style_traits"}
diff --git a/components/layout_2020/context.rs b/components/layout_2020/context.rs
index 72398d85a80..0e96797f4d7 100644
--- a/components/layout_2020/context.rs
+++ b/components/layout_2020/context.rs
@@ -2,12 +2,15 @@
* 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 gfx::font_cache_thread::FontCacheThread;
use msg::constellation_msg::PipelineId;
+use std::sync::Mutex;
use style::context::SharedStyleContext;
pub struct LayoutContext<'a> {
pub id: PipelineId,
pub style_context: SharedStyleContext<'a>,
+ pub font_cache_thread: Mutex<FontCacheThread>,
}
impl<'a> LayoutContext<'a> {
diff --git a/components/layout_2020/data.rs b/components/layout_2020/data.rs
index c406a1bc4e7..d8aa8cf77ac 100644
--- a/components/layout_2020/data.rs
+++ b/components/layout_2020/data.rs
@@ -2,17 +2,21 @@
* 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::element_data::LayoutDataForElement;
+use atomic_refcell::AtomicRefCell;
use script_layout_interface::StyleData;
#[repr(C)]
pub struct StyleAndLayoutData {
pub style_data: StyleData,
+ pub(super) layout_data: AtomicRefCell<LayoutDataForElement>,
}
impl StyleAndLayoutData {
pub fn new() -> Self {
Self {
style_data: StyleData::new(),
+ layout_data: Default::default(),
}
}
}
diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs
index 848e89ba564..0e9e18a739e 100644
--- a/components/layout_2020/dom_traversal.rs
+++ b/components/layout_2020/dom_traversal.rs
@@ -1,22 +1,28 @@
-use super::*;
-use crate::dom::{Document, NodeData, NodeId};
-use crate::style::StyleSet;
-use atomic_refcell::AtomicRefMut;
+/* 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/. */
-pub(super) struct Context<'a> {
- pub document: &'a Document,
- pub author_styles: &'a StyleSet,
-}
+use crate::element_data::{LayoutBox, LayoutDataForElement};
+use crate::replaced::ReplacedContent;
+use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOutside};
+use crate::wrapper::GetRawData;
+use atomic_refcell::AtomicRefMut;
+use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
+use servo_arc::Arc;
+use std::convert::TryInto;
+use style::context::SharedStyleContext;
+use style::dom::TNode;
+use style::properties::ComputedValues;
-#[derive(Copy, Clone)]
+#[derive(Clone, Copy)]
pub(super) enum WhichPseudoElement {
Before,
After,
}
-pub(super) enum Contents {
+pub(super) enum Contents<Node> {
/// Refers to a DOM subtree, plus `::before` and `::after` pseudo-elements.
- OfElement(NodeId),
+ OfElement(Node),
/// Example: an `<img src=…>` element.
/// <https://drafts.csswg.org/css2/conform.html#replaced-element>
@@ -27,8 +33,8 @@ pub(super) enum Contents {
OfPseudoElement(Vec<PseudoElementContentItem>),
}
-pub(super) enum NonReplacedContents {
- OfElement(NodeId),
+pub(super) enum NonReplacedContents<Node> {
+ OfElement(Node),
OfPseudoElement(Vec<PseudoElementContentItem>),
}
@@ -37,206 +43,196 @@ pub(super) enum PseudoElementContentItem {
Replaced(ReplacedContent),
}
-pub(super) trait TraversalHandler<'dom> {
- fn handle_text(&mut self, text: &str, parent_style: &Arc<ComputedValues>);
+pub(super) trait TraversalHandler<Node> {
+ fn handle_text(&mut self, text: String, parent_style: &Arc<ComputedValues>);
/// Or pseudo-element
fn handle_element(
&mut self,
style: &Arc<ComputedValues>,
display: DisplayGeneratingBox,
- contents: Contents,
- box_slot: BoxSlot<'dom>,
+ contents: Contents<Node>,
+ box_slot: BoxSlot,
);
}
-fn traverse_children_of<'dom>(
- parent_element: NodeId,
- parent_element_style: &Arc<ComputedValues>,
- context: &'dom Context,
- handler: &mut impl TraversalHandler<'dom>,
-) {
- traverse_pseudo_element(
- WhichPseudoElement::Before,
- parent_element,
- parent_element_style,
- context,
- handler,
- );
+fn traverse_children_of<'dom, Node>(
+ parent_element: Node,
+ context: &SharedStyleContext,
+ handler: &mut impl TraversalHandler<Node>,
+) where
+ Node: NodeExt<'dom>,
+{
+ traverse_pseudo_element(WhichPseudoElement::Before, parent_element, context, handler);
- let mut next = context.document[parent_element].first_child;
+ let mut next = parent_element.first_child();
while let Some(child) = next {
- match &context.document[child].data {
- NodeData::Document
- | NodeData::Doctype { .. }
- | NodeData::Comment { .. }
- | NodeData::ProcessingInstruction { .. } => {}
- NodeData::Text { contents } => {
- handler.handle_text(contents, parent_element_style);
- }
- NodeData::Element(_) => traverse_element(child, parent_element_style, context, handler),
+ if let Some(contents) = child.as_text() {
+ handler.handle_text(contents, &child.style(context));
+ } else if child.is_element() {
+ traverse_element(child, context, handler);
}
- next = context.document[child].next_sibling
+ next = child.next_sibling();
}
- traverse_pseudo_element(
- WhichPseudoElement::After,
- parent_element,
- &parent_element_style,
- context,
- handler,
- );
+ traverse_pseudo_element(WhichPseudoElement::After, parent_element, context, handler);
}
-fn traverse_element<'dom>(
- element_id: NodeId,
- parent_element_style: &ComputedValues,
- context: &'dom Context,
- handler: &mut impl TraversalHandler<'dom>,
-) {
- let style = style_for_element(
- context.author_styles,
- context.document,
- element_id,
- Some(parent_element_style),
- );
- match style.box_.display {
- Display::None => context.unset_boxes_in_subtree(element_id),
+fn traverse_element<'dom, Node>(
+ element: Node,
+ context: &SharedStyleContext,
+ handler: &mut impl TraversalHandler<Node>,
+) where
+ Node: NodeExt<'dom>,
+{
+ let style = element.style(context);
+ match Display::from(style.get_box().display) {
+ Display::None => element.unset_boxes_in_subtree(),
Display::Contents => {
- if ReplacedContent::for_element(element_id, context).is_some() {
+ if ReplacedContent::for_element(element, context).is_some() {
// `display: content` on a replaced element computes to `display: none`
// <https://drafts.csswg.org/css-display-3/#valdef-display-contents>
- context.unset_boxes_in_subtree(element_id)
+ element.unset_boxes_in_subtree()
} else {
- context.layout_data_mut(element_id).self_box = Some(LayoutBox::DisplayContents);
- traverse_children_of(element_id, &style, context, handler)
+ element.layout_data_mut().self_box = Some(LayoutBox::DisplayContents);
+ traverse_children_of(element, context, handler)
}
- }
- Display::GeneratingBox(display) => handler.handle_element(
- &style,
- display,
- match ReplacedContent::for_element(element_id, context) {
- Some(replaced) => Contents::Replaced(replaced),
- None => Contents::OfElement(element_id),
- },
- context.element_box_slot(element_id),
- ),
+ },
+ Display::GeneratingBox(display) => {
+ handler.handle_element(
+ &style,
+ display,
+ match ReplacedContent::for_element(element, context) {
+ Some(replaced) => Contents::Replaced(replaced),
+ None => Contents::OfElement(element),
+ },
+ element.element_box_slot(),
+ );
+ },
}
}
-fn traverse_pseudo_element<'dom>(
+fn traverse_pseudo_element<'dom, Node>(
which: WhichPseudoElement,
- element: NodeId,
- element_style: &ComputedValues,
- context: &'dom Context,
- handler: &mut impl TraversalHandler<'dom>,
-) {
- if let Some(style) = pseudo_element_style(which, element, element_style, context) {
- match style.box_.display {
- Display::None => context.unset_pseudo_element_box(element, which),
+ element: Node,
+ context: &SharedStyleContext,
+ handler: &mut impl TraversalHandler<Node>,
+) where
+ Node: NodeExt<'dom>,
+{
+ if let Some(style) = pseudo_element_style(which, element, context) {
+ match Display::from(style.get_box().display) {
+ Display::None => element.unset_pseudo_element_box(which),
Display::Contents => {
- context.unset_pseudo_element_box(element, which);
+ element.unset_pseudo_element_box(which);
let items = generate_pseudo_element_content(&style, element, context);
traverse_pseudo_element_contents(&style, items, handler);
- }
+ },
Display::GeneratingBox(display) => {
let items = generate_pseudo_element_content(&style, element, context);
let contents = Contents::OfPseudoElement(items);
- let box_slot = context.pseudo_element_box_slot(element, which);
+ let box_slot = element.pseudo_element_box_slot(which);
handler.handle_element(&style, display, contents, box_slot);
- }
+ },
}
}
}
-fn traverse_pseudo_element_contents<'dom>(
+fn traverse_pseudo_element_contents<'dom, Node>(
pseudo_element_style: &Arc<ComputedValues>,
items: Vec<PseudoElementContentItem>,
- handler: &mut impl TraversalHandler<'dom>,
-) {
- let mut anonymous_style = None;
+ handler: &mut impl TraversalHandler<Node>,
+) where
+ Node: 'dom,
+{
+ // let mut anonymous_style = None;
for item in items {
match item {
- PseudoElementContentItem::Text(text) => {
- handler.handle_text(&text, pseudo_element_style)
- }
+ PseudoElementContentItem::Text(text) => handler.handle_text(text, pseudo_element_style),
PseudoElementContentItem::Replaced(contents) => {
- let item_style = anonymous_style.get_or_insert_with(|| {
- ComputedValues::anonymous_inheriting_from(Some(pseudo_element_style))
- });
- let display_inline = DisplayGeneratingBox::OutsideInside {
- outside: DisplayOutside::Inline,
- inside: DisplayInside::Flow,
- };
- // `display` is not inherited, so we get the initial value
- debug_assert!(item_style.box_.display == Display::GeneratingBox(display_inline));
- handler.handle_element(
- item_style,
- display_inline,
- Contents::Replaced(contents),
- // We don’t keep pointers to boxes generated by contents of pseudo-elements
- BoxSlot::dummy(),
- )
- }
+ // FIXME
+ // let item_style = anonymous_style.get_or_insert_with(|| {
+ // ComputedValues::anonymous_inheriting_from(Some(pseudo_element_style))
+ // });
+ // let display_inline = DisplayGeneratingBox::OutsideInside {
+ // outside: DisplayOutside::Inline,
+ // inside: DisplayInside::Flow,
+ // };
+ // // `display` is not inherited, so we get the initial value
+ // debug_assert!(item_style.box_.display == Display::GeneratingBox(display_inline));
+ // handler.handle_element(
+ // item_style,
+ // display_inline,
+ // Contents::Replaced(contents),
+ // // We don’t keep pointers to boxes generated by contents of pseudo-elements
+ // BoxSlot::dummy(),
+ // )
+ },
}
}
}
-impl std::convert::TryFrom<Contents> for NonReplacedContents {
+impl<Node> std::convert::TryFrom<Contents<Node>> for NonReplacedContents<Node> {
type Error = ReplacedContent;
- fn try_from(contents: Contents) -> Result<Self, Self::Error> {
+ fn try_from(contents: Contents<Node>) -> Result<Self, Self::Error> {
match contents {
- Contents::OfElement(id) => Ok(NonReplacedContents::OfElement(id)),
+ Contents::OfElement(node) => Ok(NonReplacedContents::OfElement(node)),
Contents::OfPseudoElement(items) => Ok(NonReplacedContents::OfPseudoElement(items)),
Contents::Replaced(replaced) => Err(replaced),
}
}
}
-impl std::convert::From<NonReplacedContents> for Contents {
- fn from(contents: NonReplacedContents) -> Self {
+impl<Node> std::convert::From<NonReplacedContents<Node>> for Contents<Node> {
+ fn from(contents: NonReplacedContents<Node>) -> Self {
match contents {
- NonReplacedContents::OfElement(id) => Contents::OfElement(id),
+ NonReplacedContents::OfElement(node) => Contents::OfElement(node),
NonReplacedContents::OfPseudoElement(items) => Contents::OfPseudoElement(items),
}
}
}
-impl NonReplacedContents {
- pub fn traverse<'dom>(
+impl<'dom, Node> NonReplacedContents<Node>
+where
+ Node: NodeExt<'dom>,
+{
+ pub(crate) fn traverse(
self,
inherited_style: &Arc<ComputedValues>,
- context: &'dom Context,
- handler: &mut impl TraversalHandler<'dom>,
+ context: &SharedStyleContext,
+ handler: &mut impl TraversalHandler<Node>,
) {
match self {
- NonReplacedContents::OfElement(id) => {
- traverse_children_of(id, inherited_style, context, handler)
- }
+ NonReplacedContents::OfElement(node) => traverse_children_of(node, context, handler),
NonReplacedContents::OfPseudoElement(items) => {
traverse_pseudo_element_contents(inherited_style, items, handler)
- }
+ },
}
}
}
-fn pseudo_element_style(
+fn pseudo_element_style<'dom, Node>(
_which: WhichPseudoElement,
- _element: NodeId,
- _element_style: &ComputedValues,
- _context: &Context,
-) -> Option<Arc<ComputedValues>> {
+ _element: Node,
+ _context: &SharedStyleContext,
+) -> Option<Arc<ComputedValues>>
+where
+ Node: NodeExt<'dom>,
+{
// FIXME: run the cascade, then return None for `content: normal` or `content: none`
// https://drafts.csswg.org/css2/generate.html#content
None
}
-fn generate_pseudo_element_content(
+fn generate_pseudo_element_content<'dom, Node>(
_pseudo_element_style: &ComputedValues,
- _element: NodeId,
- _context: &Context,
-) -> Vec<PseudoElementContentItem> {
+ _element: Node,
+ _context: &SharedStyleContext,
+) -> Vec<PseudoElementContentItem>
+where
+ Node: NodeExt<'dom>,
+{
let _ = PseudoElementContentItem::Text;
let _ = PseudoElementContentItem::Replaced;
unimplemented!()
@@ -271,37 +267,77 @@ impl Drop for BoxSlot<'_> {
}
}
-impl Context<'_> {
- fn layout_data_mut(&self, element_id: NodeId) -> AtomicRefMut<LayoutDataForElement> {
- self.document[element_id]
- .as_element()
+pub(crate) trait NodeExt<'dom>: 'dom + Copy + Send + Sync {
+ fn is_element(self) -> bool;
+ fn as_text(self) -> Option<String>;
+ fn first_child(self) -> Option<Self>;
+ fn next_sibling(self) -> Option<Self>;
+ fn parent_node(self) -> Option<Self>;
+ fn style(self, context: &SharedStyleContext) -> Arc<ComputedValues>;
+
+ fn layout_data_mut(&self) -> AtomicRefMut<LayoutDataForElement>;
+ fn element_box_slot(&self) -> BoxSlot;
+ fn pseudo_element_box_slot(&self, which: WhichPseudoElement) -> BoxSlot;
+ fn unset_pseudo_element_box(self, which: WhichPseudoElement);
+ fn unset_boxes_in_subtree(self);
+}
+
+impl<'dom, T> NodeExt<'dom> for T
+where
+ T: 'dom + LayoutNode + Send + Sync,
+{
+ fn is_element(self) -> bool {
+ self.to_threadsafe().as_element().is_some()
+ }
+
+ fn as_text(self) -> Option<String> {
+ if self.is_text_node() {
+ Some(self.to_threadsafe().node_text_content())
+ } else {
+ None
+ }
+ }
+
+ fn first_child(self) -> Option<Self> {
+ TNode::first_child(&self)
+ }
+
+ fn next_sibling(self) -> Option<Self> {
+ TNode::next_sibling(&self)
+ }
+
+ fn parent_node(self) -> Option<Self> {
+ TNode::next_sibling(&self)
+ }
+
+ fn style(self, context: &SharedStyleContext) -> Arc<ComputedValues> {
+ self.to_threadsafe().style(context)
+ }
+
+ fn layout_data_mut(&self) -> AtomicRefMut<LayoutDataForElement> {
+ self.get_raw_data()
+ .map(|d| d.layout_data.borrow_mut())
.unwrap()
- .layout_data
- .borrow_mut()
}
- fn element_box_slot(&self, element_id: NodeId) -> BoxSlot {
- BoxSlot::new(AtomicRefMut::map(
- self.layout_data_mut(element_id),
- |data| &mut data.self_box,
- ))
+ fn element_box_slot(&self) -> BoxSlot {
+ BoxSlot::new(AtomicRefMut::map(self.layout_data_mut(), |data| {
+ &mut data.self_box
+ }))
}
- fn pseudo_element_box_slot(&self, element_id: NodeId, which: WhichPseudoElement) -> BoxSlot {
- BoxSlot::new(AtomicRefMut::map(
- self.layout_data_mut(element_id),
- |data| {
- let pseudos = data.pseudo_elements.get_or_insert_with(Default::default);
- match which {
- WhichPseudoElement::Before => &mut pseudos.before,
- WhichPseudoElement::After => &mut pseudos.after,
- }
- },
- ))
+ fn pseudo_element_box_slot(&self, which: WhichPseudoElement) -> BoxSlot {
+ BoxSlot::new(AtomicRefMut::map(self.layout_data_mut(), |data| {
+ let pseudos = data.pseudo_elements.get_or_insert_with(Default::default);
+ match which {
+ WhichPseudoElement::Before => &mut pseudos.before,
+ WhichPseudoElement::After => &mut pseudos.after,
+ }
+ }))
}
- fn unset_pseudo_element_box(&self, element_id: NodeId, which: WhichPseudoElement) {
- if let Some(pseudos) = &mut self.layout_data_mut(element_id).pseudo_elements {
+ fn unset_pseudo_element_box(self, which: WhichPseudoElement) {
+ if let Some(pseudos) = &mut self.layout_data_mut().pseudo_elements {
match which {
WhichPseudoElement::Before => pseudos.before = None,
WhichPseudoElement::After => pseudos.after = None,
@@ -309,34 +345,36 @@ impl Context<'_> {
}
}
- fn unset_boxes_in_subtree(&self, base_element: NodeId) {
- let mut node_id = base_element;
+ fn unset_boxes_in_subtree(self) {
+ let mut node = self;
loop {
- let node = &self.document[node_id];
- if let Some(element_data) = node.as_element() {
- let mut layout_data = element_data.layout_data.borrow_mut();
- layout_data.pseudo_elements = None;
- if layout_data.self_box.take().is_some() {
+ if node.is_element() {
+ let traverse_children = {
+ let mut layout_data = node.layout_data_mut();
+ layout_data.pseudo_elements = None;
+ layout_data.self_box.take().is_some()
+ };
+ if traverse_children {
// Only descend into children if we removed a box.
// If there wasn’t one, then descendants don’t have boxes either.
- if let Some(child) = node.first_child {
- node_id = child;
+ if let Some(child) = node.first_child() {
+ node = child;
continue;
}
}
}
- let mut next_is_a_sibling_of = node_id;
- node_id = loop {
- if let Some(sibling) = self.document[next_is_a_sibling_of].next_sibling {
+ let mut next_is_a_sibling_of = node;
+ node = loop {
+ if let Some(sibling) = next_is_a_sibling_of.next_sibling() {
break sibling;
} else {
next_is_a_sibling_of = node
- .parent
+ .parent_node()
.expect("reached the root while traversing only a subtree");
}
};
- if next_is_a_sibling_of == base_element {
- // Don’t go outside the subtree
+ if next_is_a_sibling_of == self {
+ // Don’t go outside the subtree.
return;
}
}
diff --git a/components/layout_2020/element_data.rs b/components/layout_2020/element_data.rs
index bda0d3cbe9e..17c27e1bfcd 100644
--- a/components/layout_2020/element_data.rs
+++ b/components/layout_2020/element_data.rs
@@ -1,4 +1,10 @@
-use super::*;
+/* 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::flow::inline::InlineLevelBox;
+use crate::flow::BlockLevelBox;
+use servo_arc::Arc;
#[derive(Default)]
pub(crate) struct LayoutDataForElement {
diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs
index 4acfc93ce92..de590c950d4 100644
--- a/components/layout_2020/flow/construct.rs
+++ b/components/layout_2020/flow/construct.rs
@@ -1,10 +1,27 @@
-use super::*;
+/* 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::dom_traversal::{BoxSlot, Contents, NodeExt, NonReplacedContents, TraversalHandler};
+use crate::element_data::LayoutBox;
+use crate::flow::float::FloatBox;
+use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, TextRun};
+use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
+use crate::positioned::AbsolutelyPositionedBox;
+use crate::style_ext::{DisplayGeneratingBox, DisplayInside, DisplayOutside};
+use crate::IndependentFormattingContext;
+use rayon::iter::{IntoParallelIterator, ParallelIterator};
+use rayon_croissant::ParallelIteratorExt;
+use servo_arc::Arc;
+use std::convert::TryInto;
+use style::context::SharedStyleContext;
+use style::properties::ComputedValues;
impl BlockFormattingContext {
- pub fn construct<'a>(
- context: &'a Context<'a>,
- style: &'a Arc<ComputedValues>,
- contents: NonReplacedContents,
+ pub fn construct<'dom>(
+ context: &SharedStyleContext<'_>,
+ style: &Arc<ComputedValues>,
+ contents: NonReplacedContents<impl NodeExt<'dom>>,
) -> Self {
let (contents, contains_floats) = BlockContainer::construct(context, style, contents);
Self {
@@ -14,25 +31,25 @@ impl BlockFormattingContext {
}
}
-enum IntermediateBlockLevelBox {
+enum IntermediateBlockLevelBox<Node> {
SameFormattingContextBlock {
style: Arc<ComputedValues>,
- contents: IntermediateBlockContainer,
+ contents: IntermediateBlockContainer<Node>,
},
Independent {
style: Arc<ComputedValues>,
display_inside: DisplayInside,
- contents: Contents,
+ contents: Contents<Node>,
},
OutOfFlowAbsolutelyPositionedBox {
style: Arc<ComputedValues>,
display_inside: DisplayInside,
- contents: Contents,
+ contents: Contents<Node>,
},
OutOfFlowFloatBox {
style: Arc<ComputedValues>,
display_inside: DisplayInside,
- contents: Contents,
+ contents: Contents<Node>,
},
}
@@ -43,18 +60,19 @@ enum IntermediateBlockLevelBox {
/// of a given element.
///
/// Deferring allows using rayon’s `into_par_iter`.
-enum IntermediateBlockContainer {
+enum IntermediateBlockContainer<Node> {
InlineFormattingContext(InlineFormattingContext),
- Deferred { contents: NonReplacedContents },
+ Deferred { contents: NonReplacedContents<Node> },
}
/// A builder for a block container.
///
/// This builder starts from the first child of a given DOM node
/// and does a preorder traversal of all of its inclusive siblings.
-struct BlockContainerBuilder<'a> {
- context: &'a Context<'a>,
- block_container_style: &'a Arc<ComputedValues>,
+struct BlockContainerBuilder<'dom, 'style, Node> {
+ context: &'style SharedStyleContext<'style>,
+
+ block_container_style: &'style Arc<ComputedValues>,
/// The list of block-level boxes of the final block container.
///
@@ -69,7 +87,7 @@ struct BlockContainerBuilder<'a> {
/// doesn't have a next sibling, we either reached the end of the container
/// root or there are ongoing inline-level boxes
/// (see `handle_block_level_element`).
- block_level_boxes: Vec<(IntermediateBlockLevelBox, BoxSlot<'a>)>,
+ block_level_boxes: Vec<(IntermediateBlockLevelBox<Node>, BoxSlot<'dom>)>,
/// The ongoing inline formatting context of the builder.
///
@@ -104,10 +122,10 @@ struct BlockContainerBuilder<'a> {
}
impl BlockContainer {
- pub fn construct<'a>(
- context: &'a Context<'a>,
- block_container_style: &'a Arc<ComputedValues>,
- contents: NonReplacedContents,
+ pub fn construct<'dom, 'style>(
+ context: &SharedStyleContext<'style>,
+ block_container_style: &Arc<ComputedValues>,
+ contents: NonReplacedContents<impl NodeExt<'dom>>,
) -> (BlockContainer, ContainsFloats) {
let mut builder = BlockContainerBuilder {
context,
@@ -134,7 +152,8 @@ impl BlockContainer {
);
return (container, builder.contains_floats);
}
- builder.end_ongoing_inline_formatting_context();
+ // FIXME
+ // builder.end_ongoing_inline_formatting_context();
}
let mut contains_floats = builder.contains_floats;
@@ -144,10 +163,11 @@ impl BlockContainer {
.into_par_iter()
.mapfold_reduce_into(
&mut contains_floats,
- |contains_floats, (intermediate, box_slot)| {
+ |contains_floats, (intermediate, box_slot): (IntermediateBlockLevelBox<_>, BoxSlot<'_>)| {
let (block_level_box, box_contains_floats) = intermediate.finish(context);
*contains_floats |= box_contains_floats;
- box_slot.set(LayoutBox::BlockLevel(block_level_box.clone()));
+ // FIXME
+ // box_slot.set(LayoutBox::BlockLevel(block_level_box.clone()));
block_level_box
},
|left, right| *left |= right,
@@ -158,13 +178,16 @@ impl BlockContainer {
}
}
-impl<'a> TraversalHandler<'a> for BlockContainerBuilder<'a> {
+impl<'dom, Node> TraversalHandler<Node> for BlockContainerBuilder<'dom, '_, Node>
+where
+ Node: NodeExt<'dom>,
+{
fn handle_element(
&mut self,
style: &Arc<ComputedValues>,
display: DisplayGeneratingBox,
- contents: Contents,
- box_slot: BoxSlot<'a>,
+ contents: Contents<Node>,
+ box_slot: BoxSlot,
) {
match display {
DisplayGeneratingBox::OutsideInside { outside, inside } => match outside {
@@ -172,27 +195,29 @@ impl<'a> TraversalHandler<'a> for BlockContainerBuilder<'a> {
self.handle_inline_level_element(style, inside, contents),
)),
DisplayOutside::Block => {
+ // FIXME
// Floats and abspos cause blockification, so they only happen in this case.
// https://drafts.csswg.org/css2/visuren.html#dis-pos-flo
- if style.box_.position.is_absolutely_positioned() {
- self.handle_absolutely_positioned_element(
- style.clone(),
- inside,
- contents,
- box_slot,
- )
- } else if style.box_.float.is_floating() {
- self.handle_float_element(style.clone(), inside, contents, box_slot)
- } else {
- self.handle_block_level_element(style.clone(), inside, contents, box_slot)
- }
- }
+ // if style.box_.position.is_absolutely_positioned() {
+ // self.handle_absolutely_positioned_element(
+ // style.clone(),
+ // inside,
+ // contents,
+ // box_slot,
+ // )
+ // } else if style.box_.float.is_floating() {
+ // self.handle_float_element(style.clone(), inside, contents, box_slot)
+ // } else {
+ // self.handle_block_level_element(style.clone(), inside, contents, box_slot)
+ // }
+ },
+ DisplayOutside::None => panic!(":("),
},
}
}
- fn handle_text(&mut self, input: &str, parent_style: &Arc<ComputedValues>) {
- let (leading_whitespace, mut input) = self.handle_leading_whitespace(input);
+ fn handle_text(&mut self, input: String, parent_style: &Arc<ComputedValues>) {
+ let (leading_whitespace, mut input) = self.handle_leading_whitespace(&input);
if leading_whitespace || !input.is_empty() {
// This text node should be pushed either to the next ongoing
// inline level box with the parent style of that inline level box
@@ -256,7 +281,10 @@ impl<'a> TraversalHandler<'a> for BlockContainerBuilder<'a> {
}
}
-impl<'a> BlockContainerBuilder<'a> {
+impl<'dom, Node> BlockContainerBuilder<'dom, '_, Node>
+where
+ Node: NodeExt<'dom>,
+{
/// Returns:
///
/// * Whether this text run has preserved (non-collapsible) leading whitespace
@@ -273,19 +301,19 @@ impl<'a> BlockContainerBuilder<'a> {
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::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 text = text.trim_start_matches(|c: char| c.is_ascii_whitespace());
@@ -296,7 +324,7 @@ impl<'a> BlockContainerBuilder<'a> {
&mut self,
style: &Arc<ComputedValues>,
display_inside: DisplayInside,
- contents: Contents,
+ contents: Contents<Node>,
) -> Arc<InlineLevelBox> {
let box_ = match contents.try_into() {
Err(replaced) => Arc::new(InlineLevelBox::Atomic {
@@ -322,97 +350,99 @@ impl<'a> BlockContainerBuilder<'a> {
.expect("no ongoing inline level box found");
inline_box.last_fragment = true;
Arc::new(InlineLevelBox::InlineBox(inline_box))
- }
+ },
DisplayInside::FlowRoot => {
// a.k.a. `inline-block`
unimplemented!()
- }
+ },
+ DisplayInside::None | DisplayInside::Contents => panic!(":("),
},
};
self.current_inline_level_boxes().push(box_.clone());
box_
}
- fn handle_block_level_element(
- &mut self,
- style: Arc<ComputedValues>,
- display_inside: DisplayInside,
- contents: Contents,
- box_slot: BoxSlot<'a>,
- ) {
- // We just found a block level element, all ongoing inline level boxes
- // need to be split around it. We iterate on the fragmented inline
- // level box stack to take their contents and set their first_fragment
- // field to false, for the fragmented inline level boxes that will
- // come after the block level element.
- let mut fragmented_inline_boxes =
- self.ongoing_inline_boxes_stack
- .iter_mut()
- .rev()
- .map(|ongoing| {
- let fragmented = InlineBox {
- style: ongoing.style.clone(),
- first_fragment: ongoing.first_fragment,
- // The fragmented boxes before the block level element
- // are obviously not the last fragment.
- last_fragment: false,
- children: take(&mut ongoing.children),
- };
- ongoing.first_fragment = false;
- fragmented
- });
-
- if let Some(last) = fragmented_inline_boxes.next() {
- // There were indeed some ongoing inline level boxes before
- // the block, we accumulate them as a single inline level box
- // to be pushed to the ongoing inline formatting context.
- let mut fragmented_inline = InlineLevelBox::InlineBox(last);
- for mut fragmented_parent_inline_box in fragmented_inline_boxes {
- fragmented_parent_inline_box
- .children
- .push(Arc::new(fragmented_inline));
- fragmented_inline = InlineLevelBox::InlineBox(fragmented_parent_inline_box);
- }
-
- self.ongoing_inline_formatting_context
- .inline_level_boxes
- .push(Arc::new(fragmented_inline));
- }
-
- // We found a block level element, so the ongoing inline formatting
- // context needs to be ended.
- self.end_ongoing_inline_formatting_context();
-
- let intermediate_box = match contents.try_into() {
- Ok(contents) => match display_inside {
- DisplayInside::Flow => IntermediateBlockLevelBox::SameFormattingContextBlock {
- style,
- contents: IntermediateBlockContainer::Deferred { contents },
- },
- _ => IntermediateBlockLevelBox::Independent {
- style,
- display_inside,
- contents: contents.into(),
- },
- },
- Err(contents) => {
- let contents = Contents::Replaced(contents);
- IntermediateBlockLevelBox::Independent {
- style,
- display_inside,
- contents,
- }
- }
- };
- self.block_level_boxes.push((intermediate_box, box_slot))
- }
+ // FIXME
+ // fn handle_block_level_element(
+ // &mut self,
+ // style: Arc<ComputedValues>,
+ // display_inside: DisplayInside,
+ // contents: Contents,
+ // box_slot: BoxSlot<'a>,
+ // ) {
+ // // We just found a block level element, all ongoing inline level boxes
+ // // need to be split around it. We iterate on the fragmented inline
+ // // level box stack to take their contents and set their first_fragment
+ // // field to false, for the fragmented inline level boxes that will
+ // // come after the block level element.
+ // let mut fragmented_inline_boxes =
+ // self.ongoing_inline_boxes_stack
+ // .iter_mut()
+ // .rev()
+ // .map(|ongoing| {
+ // let fragmented = InlineBox {
+ // style: ongoing.style.clone(),
+ // first_fragment: ongoing.first_fragment,
+ // // The fragmented boxes before the block level element
+ // // are obviously not the last fragment.
+ // last_fragment: false,
+ // children: take(&mut ongoing.children),
+ // };
+ // ongoing.first_fragment = false;
+ // fragmented
+ // });
+
+ // if let Some(last) = fragmented_inline_boxes.next() {
+ // // There were indeed some ongoing inline level boxes before
+ // // the block, we accumulate them as a single inline level box
+ // // to be pushed to the ongoing inline formatting context.
+ // let mut fragmented_inline = InlineLevelBox::InlineBox(last);
+ // for mut fragmented_parent_inline_box in fragmented_inline_boxes {
+ // fragmented_parent_inline_box
+ // .children
+ // .push(Arc::new(fragmented_inline));
+ // fragmented_inline = InlineLevelBox::InlineBox(fragmented_parent_inline_box);
+ // }
+
+ // self.ongoing_inline_formatting_context
+ // .inline_level_boxes
+ // .push(Arc::new(fragmented_inline));
+ // }
+
+ // // We found a block level element, so the ongoing inline formatting
+ // // context needs to be ended.
+ // self.end_ongoing_inline_formatting_context();
+
+ // let intermediate_box = match contents.try_into() {
+ // Ok(contents) => match display_inside {
+ // DisplayInside::Flow => IntermediateBlockLevelBox::SameFormattingContextBlock {
+ // style,
+ // contents: IntermediateBlockContainer::Deferred { contents },
+ // },
+ // _ => IntermediateBlockLevelBox::Independent {
+ // style,
+ // display_inside,
+ // contents: contents.into(),
+ // },
+ // },
+ // Err(contents) => {
+ // let contents = Contents::Replaced(contents);
+ // IntermediateBlockLevelBox::Independent {
+ // style,
+ // display_inside,
+ // contents,
+ // }
+ // }
+ // };
+ // self.block_level_boxes.push((intermediate_box, box_slot))
+ // }
fn handle_absolutely_positioned_element(
&mut self,
style: Arc<ComputedValues>,
display_inside: DisplayInside,
- contents: Contents,
- box_slot: BoxSlot<'a>,
+ contents: Contents<Node>,
+ box_slot: BoxSlot<'dom>,
) {
if !self.has_ongoing_inline_formatting_context() {
let box_ = IntermediateBlockLevelBox::OutOfFlowAbsolutelyPositionedBox {
@@ -420,12 +450,12 @@ impl<'a> BlockContainerBuilder<'a> {
contents,
display_inside,
};
- self.block_level_boxes.push((box_, box_slot))
+ self.block_level_boxes.push((box_, box_slot));
} else {
let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(
AbsolutelyPositionedBox {
contents: IndependentFormattingContext::construct(
- self.context,
+ unimplemented!(),
&style,
display_inside,
contents,
@@ -442,8 +472,8 @@ impl<'a> BlockContainerBuilder<'a> {
&mut self,
style: Arc<ComputedValues>,
display_inside: DisplayInside,
- contents: Contents,
- box_slot: BoxSlot<'a>,
+ contents: Contents<Node>,
+ box_slot: BoxSlot<'dom>,
) {
self.contains_floats = ContainsFloats::Yes;
@@ -485,20 +515,21 @@ impl<'a> BlockContainerBuilder<'a> {
}
let block_container_style = self.block_container_style;
- let anonymous_style = self.anonymous_style.get_or_insert_with(|| {
- // If parent_style is None, the parent is the document node,
- // in which case anonymous inline boxes should inherit their
- // styles from initial values.
- ComputedValues::anonymous_inheriting_from(Some(block_container_style))
- });
-
- let box_ = IntermediateBlockLevelBox::SameFormattingContextBlock {
- style: anonymous_style.clone(),
- contents: IntermediateBlockContainer::InlineFormattingContext(take(
- &mut self.ongoing_inline_formatting_context,
- )),
- };
- self.block_level_boxes.push((box_, BoxSlot::dummy()))
+ // FIXME
+ // let anonymous_style = self.anonymous_style.get_or_insert_with(|| {
+ // // If parent_style is None, the parent is the document node,
+ // // in which case anonymous inline boxes should inherit their
+ // // styles from initial values.
+ // ComputedValues::anonymous_inheriting_from(Some(block_container_style))
+ // });
+
+ // let box_ = IntermediateBlockLevelBox::SameFormattingContextBlock {
+ // style: anonymous_style.clone(),
+ // contents: IntermediateBlockContainer::InlineFormattingContext(take(
+ // &mut self.ongoing_inline_formatting_context,
+ // )),
+ // };
+ // self.block_level_boxes.push((box_, BoxSlot::dummy()))
}
fn current_inline_level_boxes(&mut self) -> &mut Vec<Arc<InlineLevelBox>> {
@@ -512,20 +543,26 @@ impl<'a> BlockContainerBuilder<'a> {
!self
.ongoing_inline_formatting_context
.inline_level_boxes
- .is_empty()
- || !self.ongoing_inline_boxes_stack.is_empty()
+ .is_empty() ||
+ !self.ongoing_inline_boxes_stack.is_empty()
}
}
-impl IntermediateBlockLevelBox {
- fn finish(self, context: &Context) -> (Arc<BlockLevelBox>, ContainsFloats) {
+impl<'dom, Node> IntermediateBlockLevelBox<Node>
+where
+ Node: NodeExt<'dom>,
+{
+ fn finish<'style>(
+ self,
+ context: &SharedStyleContext<'style>,
+ ) -> (Arc<BlockLevelBox>, ContainsFloats) {
match self {
IntermediateBlockLevelBox::SameFormattingContextBlock { style, contents } => {
let (contents, contains_floats) = contents.finish(context, &style);
let block_level_box =
Arc::new(BlockLevelBox::SameFormattingContextBlock { contents, style });
(block_level_box, contains_floats)
- }
+ },
IntermediateBlockLevelBox::Independent {
style,
display_inside,
@@ -541,7 +578,7 @@ impl IntermediateBlockLevelBox {
Arc::new(BlockLevelBox::Independent { style, contents }),
ContainsFloats::No,
)
- }
+ },
IntermediateBlockLevelBox::OutOfFlowAbsolutelyPositionedBox {
style,
display_inside,
@@ -559,7 +596,7 @@ impl IntermediateBlockLevelBox {
},
));
(block_level_box, ContainsFloats::No)
- }
+ },
IntermediateBlockLevelBox::OutOfFlowFloatBox {
style,
display_inside,
@@ -576,21 +613,24 @@ impl IntermediateBlockLevelBox {
style,
}));
(block_level_box, ContainsFloats::Yes)
- }
+ },
}
}
}
-impl IntermediateBlockContainer {
- fn finish(
+impl<'dom, Node> IntermediateBlockContainer<Node>
+where
+ Node: NodeExt<'dom>,
+{
+ fn finish<'style>(
self,
- context: &Context,
+ context: &SharedStyleContext<'style>,
style: &Arc<ComputedValues>,
) -> (BlockContainer, ContainsFloats) {
match self {
IntermediateBlockContainer::Deferred { contents } => {
BlockContainer::construct(context, style, contents)
- }
+ },
IntermediateBlockContainer::InlineFormattingContext(ifc) => {
// If that inline formatting context contained any float, those
// were already taken into account during the first phase of
@@ -599,13 +639,13 @@ impl IntermediateBlockContainer {
BlockContainer::InlineFormattingContext(ifc),
ContainsFloats::No,
)
- }
+ },
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub(in crate::layout) enum ContainsFloats {
+pub(crate) enum ContainsFloats {
No,
Yes,
}
diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs
index 1c06b5cf2da..31fec0b79c0 100644
--- a/components/layout_2020/flow/float.rs
+++ b/components/layout_2020/flow/float.rs
@@ -1,13 +1,19 @@
-use super::*;
+/* 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::IndependentFormattingContext;
+use servo_arc::Arc;
+use style::properties::ComputedValues;
#[derive(Debug)]
-pub(in crate::layout) struct FloatBox {
+pub(crate) struct FloatBox {
pub style: Arc<ComputedValues>,
pub contents: IndependentFormattingContext,
}
/// Data kept during layout about the floats in a given block formatting context.
-pub(in crate::layout) struct FloatContext {
+pub(crate) struct FloatContext {
// TODO
}
diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs
index 5c39bb9385b..59b822976ca 100644
--- a/components/layout_2020/flow/inline.rs
+++ b/components/layout_2020/flow/inline.rs
@@ -1,14 +1,27 @@
-use super::*;
-use crate::fonts::BITSTREAM_VERA_SANS;
-use crate::text::ShapedSegment;
+/* 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::flow::float::FloatBox;
+use crate::flow::FlowChildren;
+use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment};
+use crate::geom::flow_relative::{Rect, Sides, Vec2};
+use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment};
+use crate::replaced::ReplacedContent;
+use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
+use crate::{relative_adjustement, take, ContainingBlock};
+use servo_arc::Arc;
+use style::properties::ComputedValues;
+use style::values::computed::Length;
+use style::Zero;
#[derive(Debug, Default)]
-pub(in crate::layout) struct InlineFormattingContext {
+pub(crate) struct InlineFormattingContext {
pub(super) inline_level_boxes: Vec<Arc<InlineLevelBox>>,
}
#[derive(Debug)]
-pub(in crate::layout) enum InlineLevelBox {
+pub(crate) enum InlineLevelBox {
InlineBox(InlineBox),
TextRun(TextRun),
OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox),
@@ -21,7 +34,7 @@ pub(in crate::layout) enum InlineLevelBox {
}
#[derive(Debug)]
-pub(in crate::layout) struct InlineBox {
+pub(crate) struct InlineBox {
pub style: Arc<ComputedValues>,
pub first_fragment: bool,
pub last_fragment: bool,
@@ -30,7 +43,7 @@ pub(in crate::layout) struct InlineBox {
/// https://www.w3.org/TR/css-display-3/#css-text-run
#[derive(Debug)]
-pub(in crate::layout) struct TextRun {
+pub(crate) struct TextRun {
pub parent_style: Arc<ComputedValues>,
pub text: String,
}
@@ -93,36 +106,40 @@ impl InlineFormattingContext {
InlineLevelBox::InlineBox(inline) => {
let partial = inline.start_layout(&mut ifc);
ifc.partial_inline_boxes_stack.push(partial)
- }
+ },
InlineLevelBox::TextRun(run) => run.layout(&mut ifc),
InlineLevelBox::Atomic { style: _, contents } => {
// FIXME
match *contents {}
- }
+ },
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
- let initial_start_corner = match box_.style.specified_display {
- Display::GeneratingBox(DisplayGeneratingBox::OutsideInside {
- outside,
- inside: _,
- }) => Vec2 {
- inline: match outside {
- DisplayOutside::Inline => ifc.inline_position,
- DisplayOutside::Block => Length::zero(),
+ let initial_start_corner =
+ match Display::from(box_.style.get_box().original_display) {
+ Display::GeneratingBox(DisplayGeneratingBox::OutsideInside {
+ outside,
+ inside: _,
+ }) => Vec2 {
+ inline: match outside {
+ DisplayOutside::Inline => ifc.inline_position,
+ DisplayOutside::Block => Length::zero(),
+ DisplayOutside::None => unreachable!(":("),
+ },
+ block: ifc.line_boxes.next_line_block_position,
+ },
+ Display::Contents => {
+ panic!("display:contents does not generate an abspos box")
},
- block: ifc.line_boxes.next_line_block_position,
- },
- Display::Contents => {
- panic!("display:contents does not generate an abspos box")
- }
- Display::None => panic!("display:none does not generate an abspos box"),
- };
+ Display::None => {
+ panic!("display:none does not generate an abspos box")
+ },
+ };
absolutely_positioned_fragments
.push(box_.layout(initial_start_corner, tree_rank));
- }
+ },
InlineLevelBox::OutOfFlowFloatBox(_box_) => {
// TODO
continue;
- }
+ },
}
} else
// Reached the end of ifc.remaining_boxes
@@ -180,7 +197,7 @@ impl InlineBox {
let style = self.style.clone();
let cbis = ifc.containing_block.inline_size;
let mut padding = style.padding().percentages_relative_to(cbis);
- let mut border = style.border_width().percentages_relative_to(cbis);
+ let mut border = style.border_width();
let mut margin = style
.margin()
.percentages_relative_to(cbis)
@@ -245,9 +262,9 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
};
let last_fragment = self.last_box_tree_fragment && !at_line_break;
if last_fragment {
- *inline_position += fragment.padding.inline_end
- + fragment.border.inline_end
- + fragment.margin.inline_end;
+ *inline_position += fragment.padding.inline_end +
+ fragment.border.inline_end +
+ fragment.margin.inline_end;
} else {
fragment.padding.inline_end = Length::zero();
fragment.border.inline_end = Length::zero();
@@ -256,10 +273,10 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
self.parent_nesting_level
.max_block_size_of_fragments_so_far
.max_assign(
- fragment.content_rect.size.block
- + fragment.padding.block_sum()
- + fragment.border.block_sum()
- + fragment.margin.block_sum(),
+ fragment.content_rect.size.block +
+ fragment.padding.block_sum() +
+ fragment.border.block_sum() +
+ fragment.margin.block_sum(),
);
self.parent_nesting_level
.fragments_so_far
@@ -268,78 +285,7 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
}
impl TextRun {
- fn layout(&self, ifc: &mut InlineFormattingContextState) {
- let available = ifc.containing_block.inline_size - ifc.inline_position;
- let mut chars = self.text.chars();
- loop {
- let mut shaped = ShapedSegment::new_with_naive_shaping(BITSTREAM_VERA_SANS.clone());
- let mut last_break_opportunity = None;
- loop {
- let next = chars.next();
- if matches!(next, Some(' ') | None) {
- let inline_size = self.parent_style.font.font_size * shaped.advance_width;
- if inline_size > available {
- if let Some((state, iter)) = last_break_opportunity.take() {
- shaped.restore(&state);
- chars = iter;
- }
- break;
- }
- }
- if let Some(ch) = next {
- if ch == ' ' {
- last_break_opportunity = Some((shaped.save(), chars.clone()))
- }
- shaped.append_char(ch).unwrap()
- } else {
- break;
- }
- }
- let inline_size = self.parent_style.font.font_size * shaped.advance_width;
- // https://www.w3.org/TR/CSS2/visudet.html#propdef-line-height
- // 'normal':
- // “set the used value to a "reasonable" value based on the font of the element.”
- let line_height = self.parent_style.font.font_size.0 * 1.2;
- let content_rect = Rect {
- start_corner: Vec2 {
- block: Length::zero(),
- inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
- },
- size: Vec2 {
- block: line_height,
- inline: inline_size,
- },
- };
- ifc.inline_position += inline_size;
- ifc.current_nesting_level
- .max_block_size_of_fragments_so_far
- .max_assign(line_height);
- ifc.current_nesting_level
- .fragments_so_far
- .push(Fragment::Text(TextFragment {
- parent_style: self.parent_style.clone(),
- content_rect,
- text: shaped,
- }));
- if chars.as_str().is_empty() {
- break;
- } else {
- // New line
- 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.start_corner.inline = Length::zero();
- partial.padding.inline_start = Length::zero();
- partial.border.inline_start = Length::zero();
- partial.margin.inline_start = Length::zero();
- partial.parent_nesting_level.inline_start = Length::zero();
- nesting_level = &mut partial.parent_nesting_level;
- }
- ifc.line_boxes
- .finish_line(nesting_level, ifc.containing_block);
- ifc.inline_position = Length::zero();
- }
- }
+ fn layout(&self, _ifc: &mut InlineFormattingContextState) {
+ // TODO
}
}
diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs
index a810dfb37fa..ae92f70822c 100644
--- a/components/layout_2020/flow/mod.rs
+++ b/components/layout_2020/flow/mod.rs
@@ -1,32 +1,46 @@
+/* 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/. */
+
//! Flow layout, also known as block-and-inline layout.
-use super::*;
-use rayon::prelude::*;
+use crate::flow::float::{FloatBox, FloatContext};
+use crate::flow::inline::InlineFormattingContext;
+use crate::fragments::{
+ AnonymousFragment, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment,
+};
+use crate::geom::flow_relative::{Rect, Vec2};
+use crate::positioned::{
+ adjust_static_positions, AbsolutelyPositionedBox, AbsolutelyPositionedFragment,
+};
+use crate::style_ext::{ComputedValuesExt, Position};
+use crate::{relative_adjustement, ContainingBlock, IndependentFormattingContext};
+use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use rayon_croissant::ParallelIteratorExt;
+use servo_arc::Arc;
+use style::properties::ComputedValues;
+use style::values::computed::{Length, LengthOrAuto};
+use style::Zero;
mod construct;
mod float;
-mod inline;
+pub mod inline;
mod root;
-pub(super) use construct::*;
-pub(super) use float::*;
-pub(super) use inline::*;
-
#[derive(Debug)]
-pub(super) struct BlockFormattingContext {
+pub(crate) struct BlockFormattingContext {
pub contents: BlockContainer,
pub contains_floats: bool,
}
#[derive(Debug)]
-pub(super) enum BlockContainer {
+pub(crate) enum BlockContainer {
BlockLevelBoxes(Vec<Arc<BlockLevelBox>>),
InlineFormattingContext(InlineFormattingContext),
}
#[derive(Debug)]
-pub(super) enum BlockLevelBox {
+pub(crate) enum BlockLevelBox {
SameFormattingContextBlock {
style: Arc<ComputedValues>,
contents: BlockContainer,
@@ -98,7 +112,7 @@ impl BlockContainer {
),
BlockContainer::InlineFormattingContext(ifc) => {
ifc.layout(containing_block, tree_rank, absolutely_positioned_fragments)
- }
+ },
}
}
}
@@ -115,9 +129,9 @@ fn layout_block_level_children<'a>(
match fragment {
Fragment::Box(fragment) => {
let fragment_block_margins = &fragment.block_margins_collapsed_with_children;
- let fragment_block_size = fragment.padding.block_sum()
- + fragment.border.block_sum()
- + fragment.content_rect.size.block;
+ let fragment_block_size = fragment.padding.block_sum() +
+ fragment.border.block_sum() +
+ fragment.content_rect.size.block;
if placement_state.next_in_flow_margin_collapses_with_parent_start_margin {
assert_eq!(placement_state.current_margin.solve(), Length::zero());
@@ -136,8 +150,8 @@ fn layout_block_level_children<'a>(
.current_margin
.adjoin_assign(&fragment_block_margins.start);
}
- fragment.content_rect.start_corner.block += placement_state.current_margin.solve()
- + placement_state.current_block_direction_position;
+ fragment.content_rect.start_corner.block += placement_state.current_margin.solve() +
+ placement_state.current_block_direction_position;
if fragment_block_margins.collapsed_through {
placement_state
.current_margin
@@ -147,7 +161,7 @@ fn layout_block_level_children<'a>(
placement_state.current_block_direction_position +=
placement_state.current_margin.solve() + fragment_block_size;
placement_state.current_margin = fragment_block_margins.end;
- }
+ },
Fragment::Anonymous(fragment) => {
// FIXME(nox): Margin collapsing for hypothetical boxes of
// abspos elements is probably wrong.
@@ -155,7 +169,7 @@ fn layout_block_level_children<'a>(
assert_eq!(fragment.rect.size.block, Length::zero());
fragment.rect.start_corner.block +=
placement_state.current_block_direction_position;
- }
+ },
_ => unreachable!(),
}
}
@@ -261,12 +275,12 @@ impl BlockLevelBox {
)
},
))
- }
+ },
BlockLevelBox::Independent { style, contents } => match contents.as_replaced() {
Ok(replaced) => {
// FIXME
match *replaced {}
- }
+ },
Err(contents) => Fragment::Box(layout_in_flow_non_replaced_block_level(
containing_block,
absolutely_positioned_fragments,
@@ -280,11 +294,11 @@ impl BlockLevelBox {
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
absolutely_positioned_fragments.push(box_.layout(Vec2::zero(), tree_rank));
Fragment::Anonymous(AnonymousFragment::no_op(containing_block.mode))
- }
+ },
BlockLevelBox::OutOfFlowFloatBox(_box_) => {
// TODO
Fragment::Anonymous(AnonymousFragment::no_op(containing_block.mode))
- }
+ },
}
}
}
@@ -310,43 +324,40 @@ fn layout_in_flow_non_replaced_block_level<'a>(
) -> BoxFragment {
let cbis = containing_block.inline_size;
let padding = style.padding().percentages_relative_to(cbis);
- let border = style.border_width().percentages_relative_to(cbis);
+ let border = style.border_width();
let mut computed_margin = style.margin().percentages_relative_to(cbis);
let pb = &padding + &border;
let box_size = style.box_size();
let inline_size = box_size.inline.percentage_relative_to(cbis);
- if let LengthOrAuto::Length(is) = inline_size {
+ if let LengthOrAuto::LengthPercentage(is) = inline_size {
let inline_margins = cbis - is - pb.inline_sum();
- use LengthOrAuto::*;
match (
&mut computed_margin.inline_start,
&mut computed_margin.inline_end,
) {
- (s @ &mut Auto, e @ &mut Auto) => {
- *s = Length(inline_margins / 2.);
- *e = Length(inline_margins / 2.);
- }
- (s @ &mut Auto, _) => {
- *s = Length(inline_margins);
- }
- (_, e @ &mut Auto) => {
- *e = Length(inline_margins);
- }
+ (s @ &mut LengthOrAuto::Auto, e @ &mut LengthOrAuto::Auto) => {
+ *s = LengthOrAuto::LengthPercentage(inline_margins / 2.);
+ *e = LengthOrAuto::LengthPercentage(inline_margins / 2.);
+ },
+ (s @ &mut LengthOrAuto::Auto, _) => {
+ *s = LengthOrAuto::LengthPercentage(inline_margins);
+ },
+ (_, e @ &mut LengthOrAuto::Auto) => {
+ *e = LengthOrAuto::LengthPercentage(inline_margins);
+ },
(_, e @ _) => {
// Either the inline-end margin is auto,
// or we’re over-constrained and we do as if it were.
- *e = Length(inline_margins);
- }
+ *e = LengthOrAuto::LengthPercentage(inline_margins);
+ },
}
}
let margin = computed_margin.auto_is(Length::zero);
let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
let inline_size = inline_size.auto_is(|| cbis - pb.inline_sum() - margin.inline_sum());
- let block_size = match box_size.block {
- LengthOrPercentageOrAuto::Length(l) => LengthOrAuto::Length(l),
- LengthOrPercentageOrAuto::Percentage(p) => containing_block.block_size.map(|cbbs| cbbs * p),
- LengthOrPercentageOrAuto::Auto => LengthOrAuto::Auto,
- };
+ let block_size = box_size
+ .block
+ .maybe_percentage_relative_to(containing_block.block_size.non_auto());
let containing_block_for_children = ContainingBlock {
inline_size,
block_size,
@@ -358,11 +369,11 @@ fn layout_in_flow_non_replaced_block_level<'a>(
"Mixed writing modes are not supported yet"
);
let this_start_margin_can_collapse_with_children = CollapsibleWithParentStartMargin(
- block_level_kind == BlockLevelKind::SameFormattingContextBlock
- && pb.block_start == Length::zero(),
+ block_level_kind == BlockLevelKind::SameFormattingContextBlock &&
+ pb.block_start == Length::zero(),
);
- let this_end_margin_can_collapse_with_children = (block_level_kind, pb.block_end, block_size)
- == (
+ let this_end_margin_can_collapse_with_children = (block_level_kind, pb.block_end, block_size) ==
+ (
BlockLevelKind::SameFormattingContextBlock,
Length::zero(),
LengthOrAuto::Auto,
@@ -370,7 +381,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
let mut nested_abspos = vec![];
let mut flow_children = layout_contents(
&containing_block_for_children,
- if style.box_.position.is_relatively_positioned() {
+ if style.get_box().position == Position::Relative {
&mut nested_abspos
} else {
absolutely_positioned_fragments
@@ -401,9 +412,9 @@ fn layout_in_flow_non_replaced_block_level<'a>(
flow_children.block_size += flow_children.collapsible_margins_in_children.end.solve();
}
block_margins_collapsed_with_children.collapsed_through =
- this_start_margin_can_collapse_with_children.0
- && this_end_margin_can_collapse_with_children
- && flow_children
+ this_start_margin_can_collapse_with_children.0 &&
+ this_end_margin_can_collapse_with_children &&
+ flow_children
.collapsible_margins_in_children
.collapsed_through;
let relative_adjustement = relative_adjustement(style, inline_size, block_size);
@@ -418,7 +429,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
inline: inline_size,
},
};
- if style.box_.position.is_relatively_positioned() {
+ if style.get_box().position == Position::Relative {
AbsolutelyPositionedFragment::in_positioned_containing_block(
&nested_abspos,
&mut flow_children.fragments,
diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs
index 443969c2acb..08a23397506 100644
--- a/components/layout_2020/flow/root.rs
+++ b/components/layout_2020/flow/root.rs
@@ -1,122 +1,129 @@
+/* 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 super::*;
-impl crate::dom::Document {
- pub(crate) fn layout(
- &self,
- viewport: crate::primitives::Size<crate::primitives::CssPx>,
- ) -> Vec<Fragment> {
- BoxTreeRoot::construct(self).layout(viewport)
- }
-}
+// FIXME
+// impl crate::dom::Document {
+// pub(crate) fn layout(
+// &self,
+// viewport: crate::geom::Size<crate::geom::CssPx>,
+// ) -> Vec<Fragment> {
+// BoxTreeRoot::construct(self).layout(viewport)
+// }
+// }
struct BoxTreeRoot(BlockFormattingContext);
-impl BoxTreeRoot {
- pub fn construct(document: &dom::Document) -> Self {
- let author_styles = &document.parse_stylesheets();
- let context = Context {
- document,
- author_styles,
- };
- let root_element = document.root_element();
- let style = style_for_element(context.author_styles, context.document, root_element, None);
- let (contains_floats, boxes) = construct_for_root_element(&context, root_element, style);
- Self(BlockFormattingContext {
- contains_floats: contains_floats == ContainsFloats::Yes,
- contents: BlockContainer::BlockLevelBoxes(boxes),
- })
- }
-}
+// FIXME
+// impl BoxTreeRoot {
+// pub fn construct(document: &dom::Document) -> Self {
+// let author_styles = &document.parse_stylesheets();
+// let context = Context {
+// document,
+// author_styles,
+// };
+// let root_element = document.root_element();
+// let style = style_for_element(context.author_styles, context.document, root_element, None);
+// let (contains_floats, boxes) = construct_for_root_element(&context, root_element, style);
+// Self(BlockFormattingContext {
+// contains_floats: contains_floats == ContainsFloats::Yes,
+// contents: BlockContainer::BlockLevelBoxes(boxes),
+// })
+// }
+// }
-fn construct_for_root_element(
- context: &Context,
- root_element: dom::NodeId,
- style: Arc<ComputedValues>,
-) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
- let replaced = ReplacedContent::for_element(root_element, context);
+// fn construct_for_root_element(
+// context: &Context,
+// root_element: dom::NodeId,
+// style: Arc<ComputedValues>,
+// ) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
+// let replaced = ReplacedContent::for_element(root_element, context);
- let display_inside = match style.box_.display {
- Display::None => return (ContainsFloats::No, Vec::new()),
- Display::Contents if replaced.is_some() => {
- // 'display: contents' computes to 'none' for replaced elements
- return (ContainsFloats::No, Vec::new());
- }
- // https://drafts.csswg.org/css-display-3/#transformations
- Display::Contents => DisplayInside::Flow,
- // The root element is blockified, ignore DisplayOutside
- Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
- };
+// let display_inside = match style.box_.display {
+// Display::None => return (ContainsFloats::No, Vec::new()),
+// Display::Contents if replaced.is_some() => {
+// // 'display: contents' computes to 'none' for replaced elements
+// return (ContainsFloats::No, Vec::new());
+// }
+// // https://drafts.csswg.org/css-display-3/#transformations
+// Display::Contents => DisplayInside::Flow,
+// // The root element is blockified, ignore DisplayOutside
+// Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
+// };
- if let Some(replaced) = replaced {
- let _box = match replaced {};
- #[allow(unreachable_code)]
- {
- return (ContainsFloats::No, vec![Arc::new(_box)]);
- }
- }
+// if let Some(replaced) = replaced {
+// let _box = match replaced {};
+// #[allow(unreachable_code)]
+// {
+// return (ContainsFloats::No, vec![Arc::new(_box)]);
+// }
+// }
- let contents = IndependentFormattingContext::construct(
- context,
- &style,
- display_inside,
- Contents::OfElement(root_element),
- );
- if style.box_.position.is_absolutely_positioned() {
- (
- ContainsFloats::No,
- vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
- AbsolutelyPositionedBox { style, contents },
- ))],
- )
- } else if style.box_.float.is_floating() {
- (
- ContainsFloats::Yes,
- vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox {
- contents,
- style,
- }))],
- )
- } else {
- (
- ContainsFloats::No,
- vec![Arc::new(BlockLevelBox::Independent { style, contents })],
- )
- }
-}
+// let contents = IndependentFormattingContext::construct(
+// context,
+// &style,
+// display_inside,
+// Contents::OfElement(root_element),
+// );
+// if style.box_.position.is_absolutely_positioned() {
+// (
+// ContainsFloats::No,
+// vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
+// AbsolutelyPositionedBox { style, contents },
+// ))],
+// )
+// } else if style.box_.float.is_floating() {
+// (
+// ContainsFloats::Yes,
+// vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox {
+// contents,
+// style,
+// }))],
+// )
+// } else {
+// (
+// ContainsFloats::No,
+// vec![Arc::new(BlockLevelBox::Independent { style, contents })],
+// )
+// }
+// }
-impl BoxTreeRoot {
- fn layout(&self, viewport: crate::primitives::Size<crate::primitives::CssPx>) -> Vec<Fragment> {
- let initial_containing_block_size = Vec2 {
- inline: Length { px: viewport.width },
- block: Length {
- px: viewport.height,
- },
- };
+// impl BoxTreeRoot {
+// fn layout(&self, viewport: crate::geom::Size<crate::geom::CssPx>) -> Vec<Fragment> {
+// let initial_containing_block_size = Vec2 {
+// inline: Length { px: viewport.width },
+// block: Length {
+// px: viewport.height,
+// },
+// };
- let initial_containing_block = ContainingBlock {
- inline_size: initial_containing_block_size.inline,
- block_size: LengthOrAuto::Length(initial_containing_block_size.block),
- // FIXME: use the document’s mode:
- // https://drafts.csswg.org/css-writing-modes/#principal-flow
- mode: (WritingMode::HorizontalTb, Direction::Ltr),
- };
- let dummy_tree_rank = 0;
- let mut absolutely_positioned_fragments = vec![];
- let mut flow_children = self.0.layout(
- &initial_containing_block,
- dummy_tree_rank,
- &mut absolutely_positioned_fragments,
- );
+// let initial_containing_block = ContainingBlock {
+// inline_size: initial_containing_block_size.inline,
+// block_size: LengthOrAuto::Length(initial_containing_block_size.block),
+// // FIXME: use the document’s mode:
+// // https://drafts.csswg.org/css-writing-modes/#principal-flow
+// mode: (WritingMode::HorizontalTb, Direction::Ltr),
+// };
+// let dummy_tree_rank = 0;
+// let mut absolutely_positioned_fragments = vec![];
+// let mut fragments = self.0.layout(
+// &initial_containing_block,
+// &mut absolutely_positioned_fragments,
+// dummy_tree_rank,
+// &mut PlacementState::root(),
+// );
- let initial_containing_block = DefiniteContainingBlock {
- size: initial_containing_block_size,
- mode: initial_containing_block.mode,
- };
- flow_children.fragments.par_extend(
- absolutely_positioned_fragments
- .par_iter()
- .map(|a| a.layout(&initial_containing_block)),
- );
- flow_children.fragments
- }
-}
+// let initial_containing_block = DefiniteContainingBlock {
+// size: initial_containing_block_size,
+// mode: initial_containing_block.mode,
+// };
+// fragments.par_extend(
+// absolutely_positioned_fragments
+// .par_iter()
+// .map(|a| a.layout(&initial_containing_block)),
+// );
+// fragments
+// }
+// }
diff --git a/components/layout_2020/fragments.rs b/components/layout_2020/fragments.rs
index f2a4dcd2986..ceb2fdf7971 100644
--- a/components/layout_2020/fragments.rs
+++ b/components/layout_2020/fragments.rs
@@ -1,5 +1,14 @@
-use super::*;
-use crate::text::ShapedSegment;
+/* 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::geom::flow_relative::{Rect, Sides};
+use crate::style_ext::{Direction, WritingMode};
+// use crate::text::ShapedSegment;
+use servo_arc::Arc;
+use style::properties::ComputedValues;
+use style::values::computed::Length;
+use style::Zero;
pub(crate) enum Fragment {
Box(BoxFragment),
@@ -45,7 +54,7 @@ pub(crate) struct AnonymousFragment {
pub(crate) struct TextFragment {
pub parent_style: Arc<ComputedValues>,
pub content_rect: Rect<Length>,
- pub text: ShapedSegment,
+ // pub text: ShapedSegment,
}
impl AnonymousFragment {
diff --git a/components/layout_2020/geom.rs b/components/layout_2020/geom.rs
index 2032a3e72ab..af8d37393b5 100644
--- a/components/layout_2020/geom.rs
+++ b/components/layout_2020/geom.rs
@@ -1,20 +1,31 @@
-pub(crate) use crate::style::values::Length;
-use crate::style::values::{LengthOrAuto, LengthOrPercentage, LengthOrPercentageOrAuto};
+/* 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::style_ext::{Direction, WritingMode};
+use std::ops::{Add, AddAssign, Sub};
+use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
+use style::Zero;
+use style_traits::CSSPixel;
+
+pub type Point<U> = euclid::Point2D<f32, U>;
+pub type Size<U> = euclid::Size2D<f32, U>;
+pub type Rect<U> = euclid::Rect<f32, U>;
pub(crate) mod physical {
- #[derive(Debug, Clone)]
+ #[derive(Clone, Debug)]
pub(crate) struct Vec2<T> {
pub x: T,
pub y: T,
}
- #[derive(Debug, Clone)]
+ #[derive(Clone, Debug)]
pub(crate) struct Rect<T> {
pub top_left: Vec2<T>,
pub size: Vec2<T>,
}
- #[derive(Debug, Clone)]
+ #[derive(Clone, Debug)]
pub(crate) struct Sides<T> {
pub top: T,
pub left: T,
@@ -24,19 +35,19 @@ pub(crate) mod physical {
}
pub(crate) mod flow_relative {
- #[derive(Debug, Clone)]
+ #[derive(Clone, Debug)]
pub(crate) struct Vec2<T> {
pub inline: T,
pub block: T,
}
- #[derive(Debug, Clone)]
+ #[derive(Clone, Debug)]
pub(crate) struct Rect<T> {
pub start_corner: Vec2<T>,
pub size: Vec2<T>,
}
- #[derive(Debug, Clone)]
+ #[derive(Clone, Debug)]
pub(crate) struct Sides<T> {
pub inline_start: T,
pub inline_end: T,
@@ -45,9 +56,6 @@ pub(crate) mod flow_relative {
}
}
-use crate::style::values::{Direction, WritingMode};
-use std::ops::{Add, AddAssign, Sub};
-
impl<T> Add<&'_ physical::Vec2<T>> for &'_ physical::Vec2<T>
where
T: Add<Output = T> + Copy,
@@ -145,9 +153,9 @@ impl<T: Clone> flow_relative::Vec2<T> {
}
}
-impl From<physical::Vec2<Length>> for crate::primitives::Point<crate::primitives::CssPx> {
+impl From<physical::Vec2<Length>> for Point<CSSPixel> {
fn from(v: physical::Vec2<Length>) -> Self {
- crate::primitives::Point::from_lengths(v.x.into(), v.y.into())
+ Point::from_lengths(v.x.into(), v.y.into())
}
}
@@ -159,18 +167,14 @@ impl<T: Clone> physical::Sides<T> {
// https://drafts.csswg.org/css-writing-modes/#logical-to-physical
let (bs, be) = match mode.0 {
HorizontalTb => (&self.top, &self.bottom),
- VerticalRl | SidewaysRl => (&self.right, &self.left),
- VerticalLr | SidewaysLr => (&self.left, &self.right),
+ VerticalRl => (&self.right, &self.left),
+ VerticalLr => (&self.left, &self.right),
};
let (is, ie) = match mode {
(HorizontalTb, Ltr) => (&self.left, &self.right),
(HorizontalTb, Rtl) => (&self.right, &self.left),
- (VerticalRl, Ltr) | (SidewaysRl, Ltr) | (VerticalLr, Ltr) | (SidewaysLr, Rtl) => {
- (&self.top, &self.bottom)
- }
- (VerticalRl, Rtl) | (SidewaysRl, Rtl) | (VerticalLr, Rtl) | (SidewaysLr, Ltr) => {
- (&self.bottom, &self.top)
- }
+ (VerticalRl, Ltr) | (VerticalLr, Ltr) => (&self.top, &self.bottom),
+ (VerticalRl, Rtl) | (VerticalLr, Rtl) => (&self.bottom, &self.top),
};
flow_relative::Sides {
inline_start: is.clone(),
@@ -229,13 +233,13 @@ impl<T> flow_relative::Sides<T> {
}
}
-impl flow_relative::Sides<LengthOrPercentage> {
+impl flow_relative::Sides<LengthPercentage> {
pub fn percentages_relative_to(&self, basis: Length) -> flow_relative::Sides<Length> {
self.map(|s| s.percentage_relative_to(basis))
}
}
-impl flow_relative::Sides<LengthOrPercentageOrAuto> {
+impl flow_relative::Sides<LengthPercentageOrAuto> {
pub fn percentages_relative_to(&self, basis: Length) -> flow_relative::Sides<LengthOrAuto> {
self.map(|s| s.percentage_relative_to(basis))
}
@@ -320,11 +324,11 @@ impl<T> physical::Rect<T> {
}
}
-impl From<physical::Rect<Length>> for crate::primitives::Rect<crate::primitives::CssPx> {
+impl From<physical::Rect<Length>> for Rect<CSSPixel> {
fn from(r: physical::Rect<Length>) -> Self {
- crate::primitives::Rect {
- origin: crate::primitives::Point::new(r.top_left.x.px, r.top_left.y.px),
- size: crate::primitives::Size::new(r.size.x.px, r.size.y.px),
+ Rect {
+ origin: Point::new(r.top_left.x.px(), r.top_left.y.px()),
+ size: Size::new(r.size.x.px(), r.size.y.px()),
}
}
}
diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs
index af5709eae38..05a5caa9771 100644
--- a/components/layout_2020/lib.rs
+++ b/components/layout_2020/lib.rs
@@ -2,11 +2,159 @@
* 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/. */
+#![allow(dead_code)]
+#![allow(unreachable_code)]
+#![allow(unused_imports)]
+#![allow(unused_variables)]
#![deny(unsafe_code)]
+#[macro_use]
+extern crate serde;
+
+use style::properties::ComputedValues;
+use style::values::computed::{Length, LengthOrAuto};
+use style::Zero;
+
pub mod context;
pub mod data;
+pub mod dom_traversal;
+pub mod element_data;
+pub mod flow;
+pub mod fragments;
+pub mod geom;
pub mod opaque_node;
+pub mod positioned;
pub mod query;
+pub mod replaced;
+pub mod style_ext;
pub mod traversal;
pub mod wrapper;
+
+use crate::dom_traversal::{Contents, NodeExt};
+use crate::flow::{BlockFormattingContext, FlowChildren};
+use crate::geom::flow_relative::Vec2;
+use crate::positioned::AbsolutelyPositionedFragment;
+use crate::replaced::ReplacedContent;
+use crate::style_ext::{ComputedValuesExt, Direction, Position, WritingMode};
+use servo_arc::Arc;
+use std::convert::TryInto;
+use style::context::SharedStyleContext;
+use style::values::specified::box_::DisplayInside;
+
+/// https://drafts.csswg.org/css-display/#independent-formatting-context
+#[derive(Debug)]
+enum IndependentFormattingContext {
+ Flow(BlockFormattingContext),
+
+ // Not called FC in specs, but behaves close enough
+ Replaced(ReplacedContent),
+ // Other layout modes go here
+}
+
+enum NonReplacedIFC<'a> {
+ Flow(&'a BlockFormattingContext),
+}
+
+impl IndependentFormattingContext {
+ fn construct<'dom, 'style>(
+ context: &SharedStyleContext<'style>,
+ style: &Arc<ComputedValues>,
+ display_inside: DisplayInside,
+ contents: Contents<impl NodeExt<'dom>>,
+ ) -> Self {
+ match contents.try_into() {
+ Ok(non_replaced) => match display_inside {
+ DisplayInside::Flow | DisplayInside::FlowRoot => {
+ IndependentFormattingContext::Flow(BlockFormattingContext::construct(
+ context,
+ style,
+ non_replaced,
+ ))
+ },
+ DisplayInside::None | DisplayInside::Contents => panic!(":("),
+ },
+ Err(replaced) => IndependentFormattingContext::Replaced(replaced),
+ }
+ }
+
+ fn as_replaced(&self) -> Result<&ReplacedContent, NonReplacedIFC> {
+ match self {
+ IndependentFormattingContext::Replaced(r) => Ok(r),
+ IndependentFormattingContext::Flow(f) => Err(NonReplacedIFC::Flow(f)),
+ }
+ }
+
+ fn layout<'a>(
+ &'a self,
+ containing_block: &ContainingBlock,
+ tree_rank: usize,
+ absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
+ ) -> FlowChildren {
+ match self.as_replaced() {
+ Ok(replaced) => match *replaced {},
+ Err(ifc) => ifc.layout(containing_block, tree_rank, absolutely_positioned_fragments),
+ }
+ }
+}
+
+impl<'a> NonReplacedIFC<'a> {
+ fn layout(
+ &self,
+ containing_block: &ContainingBlock,
+ tree_rank: usize,
+ absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
+ ) -> FlowChildren {
+ match self {
+ NonReplacedIFC::Flow(bfc) => {
+ bfc.layout(containing_block, tree_rank, absolutely_positioned_fragments)
+ },
+ }
+ }
+}
+
+struct ContainingBlock {
+ inline_size: Length,
+ block_size: LengthOrAuto,
+ mode: (WritingMode, Direction),
+}
+
+struct DefiniteContainingBlock {
+ size: Vec2<Length>,
+ mode: (WritingMode, Direction),
+}
+
+/// https://drafts.csswg.org/css2/visuren.html#relative-positioning
+fn relative_adjustement(
+ style: &ComputedValues,
+ inline_size: Length,
+ block_size: LengthOrAuto,
+) -> Vec2<Length> {
+ if style.get_box().position != Position::Relative {
+ return Vec2::zero();
+ }
+ fn adjust(start: LengthOrAuto, end: LengthOrAuto) -> Length {
+ match (start, end) {
+ (LengthOrAuto::Auto, LengthOrAuto::Auto) => Length::zero(),
+ (LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => -end,
+ (LengthOrAuto::LengthPercentage(start), _) => start,
+ }
+ }
+ let block_size = block_size.auto_is(Length::zero);
+ let box_offsets = style.box_offsets().map_inline_and_block_axes(
+ |v| v.percentage_relative_to(inline_size),
+ |v| v.percentage_relative_to(block_size),
+ );
+ Vec2 {
+ inline: adjust(box_offsets.inline_start, box_offsets.inline_end),
+ block: adjust(box_offsets.block_start, box_offsets.block_end),
+ }
+}
+
+// FIXME: use std::mem::take when it’s stable.
+// https://github.com/rust-lang/rust/issues/61129
+fn take<T>(x: &mut T) -> T
+where
+ T: Default,
+{
+ std::mem::replace(x, Default::default())
+}
diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs
index 9794d1acdae..55888fb8842 100644
--- a/components/layout_2020/positioned.rs
+++ b/components/layout_2020/positioned.rs
@@ -1,30 +1,41 @@
-use super::*;
-use rayon::prelude::*;
+/* 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::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment};
+use crate::geom::flow_relative::{Rect, Sides, Vec2};
+use crate::style_ext::{ComputedValuesExt, Direction, WritingMode};
+use crate::{ContainingBlock, DefiniteContainingBlock, IndependentFormattingContext};
+use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
+use servo_arc::Arc;
+use style::properties::ComputedValues;
+use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
+use style::Zero;
#[derive(Debug)]
-pub(super) struct AbsolutelyPositionedBox {
+pub(crate) struct AbsolutelyPositionedBox {
pub style: Arc<ComputedValues>,
pub contents: IndependentFormattingContext,
}
#[derive(Debug)]
-pub(super) struct AbsolutelyPositionedFragment<'box_> {
+pub(crate) struct AbsolutelyPositionedFragment<'box_> {
absolutely_positioned_box: &'box_ AbsolutelyPositionedBox,
/// The rank of the child from which this absolutely positioned fragment
/// came from, when doing the layout of a block container. Used to compute
/// static positions when going up the tree.
- pub(super) tree_rank: usize,
+ pub(crate) tree_rank: usize,
- pub(super) inline_start: AbsoluteBoxOffsets<LengthOrPercentage>,
- inline_size: LengthOrPercentageOrAuto,
+ pub(crate) inline_start: AbsoluteBoxOffsets<LengthPercentage>,
+ inline_size: LengthPercentageOrAuto,
- pub(super) block_start: AbsoluteBoxOffsets<LengthOrPercentage>,
- block_size: LengthOrPercentageOrAuto,
+ pub(crate) block_start: AbsoluteBoxOffsets<LengthPercentage>,
+ block_size: LengthPercentageOrAuto,
}
#[derive(Clone, Copy, Debug)]
-pub(super) enum AbsoluteBoxOffsets<NonStatic> {
+pub(crate) enum AbsoluteBoxOffsets<NonStatic> {
StaticStart { start: Length },
Start { start: NonStatic },
End { end: NonStatic },
@@ -32,7 +43,7 @@ pub(super) enum AbsoluteBoxOffsets<NonStatic> {
}
impl AbsolutelyPositionedBox {
- pub(super) fn layout<'a>(
+ pub(crate) fn layout<'a>(
&'a self,
initial_start_corner: Vec2<Length>,
tree_rank: usize,
@@ -46,9 +57,9 @@ impl AbsolutelyPositionedBox {
fn absolute_box_offsets(
initial_static_start: Length,
- start: LengthOrPercentageOrAuto,
- end: LengthOrPercentageOrAuto,
- ) -> AbsoluteBoxOffsets<LengthOrPercentage> {
+ start: LengthPercentageOrAuto,
+ end: LengthPercentageOrAuto,
+ ) -> AbsoluteBoxOffsets<LengthPercentage> {
match (start.non_auto(), end.non_auto()) {
(None, None) => AbsoluteBoxOffsets::StaticStart {
start: initial_static_start,
@@ -82,7 +93,7 @@ impl AbsolutelyPositionedBox {
}
impl<'a> AbsolutelyPositionedFragment<'a> {
- pub(super) fn in_positioned_containing_block(
+ pub(crate) fn in_positioned_containing_block(
absolute: &[Self],
fragments: &mut Vec<Fragment>,
content_rect_size: &Vec2<Length>,
@@ -112,13 +123,13 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
}))
}
- pub(super) fn layout(&self, containing_block: &DefiniteContainingBlock) -> Fragment {
+ pub(crate) fn layout(&self, containing_block: &DefiniteContainingBlock) -> Fragment {
let style = &self.absolutely_positioned_box.style;
let cbis = containing_block.size.inline;
let cbbs = containing_block.size.block;
let padding = style.padding().percentages_relative_to(cbis);
- let border = style.border_width().percentages_relative_to(cbis);
+ let border = style.border_width();
let computed_margin = style.margin().percentages_relative_to(cbis);
let pb = &padding + &border;
@@ -133,8 +144,8 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
computed_margin_start: LengthOrAuto,
computed_margin_end: LengthOrAuto,
solve_margins: impl FnOnce(Length) -> (Length, Length),
- box_offsets: AbsoluteBoxOffsets<LengthOrPercentage>,
- size: LengthOrPercentageOrAuto,
+ box_offsets: AbsoluteBoxOffsets<LengthPercentage>,
+ size: LengthPercentageOrAuto,
) -> (Anchor, LengthOrAuto, Length, Length) {
let size = size.percentage_relative_to(containing_size);
match box_offsets {
@@ -163,40 +174,42 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
let mut margin_start = computed_margin_start.auto_is(Length::zero);
let mut margin_end = computed_margin_end.auto_is(Length::zero);
- let size = if let LengthOrAuto::Length(size) = size {
- use LengthOrAuto::Auto;
+ let size = if let LengthOrAuto::LengthPercentage(size) = size {
let margins = containing_size - start - end - padding_border_sum - size;
match (computed_margin_start, computed_margin_end) {
- (Auto, Auto) => {
+ (LengthOrAuto::Auto, LengthOrAuto::Auto) => {
let (s, e) = solve_margins(margins);
margin_start = s;
margin_end = e;
- }
- (Auto, LengthOrAuto::Length(end)) => {
+ },
+ (LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => {
margin_start = margins - end;
- }
- (LengthOrAuto::Length(start), Auto) => {
+ },
+ (LengthOrAuto::LengthPercentage(start), LengthOrAuto::Auto) => {
margin_end = margins - start;
- }
- (LengthOrAuto::Length(_), LengthOrAuto::Length(_)) => {}
+ },
+ (
+ LengthOrAuto::LengthPercentage(_),
+ LengthOrAuto::LengthPercentage(_),
+ ) => {},
}
size
} else {
// FIXME(nox): What happens if that is negative?
- containing_size
- - start
- - end
- - padding_border_sum
- - margin_start
- - margin_end
+ containing_size -
+ start -
+ end -
+ padding_border_sum -
+ margin_start -
+ margin_end
};
(
Anchor::Start(start),
- LengthOrAuto::Length(size),
+ LengthOrAuto::LengthPercentage(size),
margin_start,
margin_end,
)
- }
+ },
}
}
@@ -206,7 +219,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
computed_margin.inline_start,
computed_margin.inline_end,
|margins| {
- if margins.px >= 0. {
+ if margins.px() >= 0. {
(margins / 2., margins / 2.)
} else {
(Length::zero(), margins)
@@ -303,7 +316,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
}
}
-pub(super) fn adjust_static_positions(
+pub(crate) fn adjust_static_positions(
absolutely_positioned_fragments: &mut [AbsolutelyPositionedFragment],
child_fragments: &mut [Fragment],
tree_rank_in_parent: usize,
diff --git a/components/layout_2020/primitives.rs b/components/layout_2020/primitives.rs
deleted file mode 100644
index 0991478ac06..00000000000
--- a/components/layout_2020/primitives.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-use crate::text;
-
-/// Origin at top-left corner, unit `1px`
-pub struct CssPx;
-
-pub use euclid::point2 as point;
-pub use euclid::rect;
-pub type Length<U> = euclid::Length<f32, U>;
-pub type Point<U> = euclid::TypedPoint2D<f32, U>;
-pub type Size<U> = euclid::TypedSize2D<f32, U>;
-pub type Rect<U> = euclid::TypedRect<f32, U>;
-pub type SideOffsets<U> = euclid::TypedSideOffsets2D<f32, U>;
-pub type Scale<Src, Dest> = euclid::TypedScale<f32, Src, Dest>;
-
-#[derive(Copy, Clone, PartialEq)]
-pub struct RGBA(pub f32, pub f32, pub f32, pub f32);
-
-pub struct TextRun<'a> {
- pub segment: &'a text::ShapedSegment,
- pub font_size: Length<CssPx>,
- pub origin: Point<CssPx>,
-}
-
-impl From<cssparser::RGBA> for RGBA {
- fn from(c: cssparser::RGBA) -> Self {
- RGBA(c.red_f32(), c.green_f32(), c.blue_f32(), c.alpha_f32())
- }
-}
diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs
index 312326c84af..04defc26b02 100644
--- a/components/layout_2020/replaced.rs
+++ b/components/layout_2020/replaced.rs
@@ -1,5 +1,9 @@
-use super::*;
-use crate::dom::NodeId;
+/* 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::dom_traversal::NodeExt;
+use style::context::SharedStyleContext;
#[derive(Debug)]
pub(super) enum ReplacedContent {
@@ -7,7 +11,10 @@ pub(super) enum ReplacedContent {
}
impl ReplacedContent {
- pub fn for_element(_element: NodeId, _context: &Context) -> Option<Self> {
+ pub fn for_element<'dom, Node>(element: Node, _context: &SharedStyleContext) -> Option<Self>
+ where
+ Node: NodeExt<'dom>,
+ {
// FIXME: implement <img> etc.
None
}
diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs
new file mode 100644
index 00000000000..bb0b0411dec
--- /dev/null
+++ b/components/layout_2020/style_ext.rs
@@ -0,0 +1,129 @@
+/* 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::geom::{flow_relative, physical};
+use style::properties::ComputedValues;
+use style::values::computed::{
+ Display as PackedDisplay, Length, LengthPercentage, LengthPercentageOrAuto, Size,
+};
+
+pub use style::computed_values::direction::T as Direction;
+pub use style::computed_values::position::T as Position;
+pub use style::computed_values::writing_mode::T as WritingMode;
+pub use style::values::specified::box_::{DisplayInside, DisplayOutside};
+
+#[derive(Clone, Copy, Eq, PartialEq)]
+pub(crate) enum Display {
+ None,
+ Contents,
+ GeneratingBox(DisplayGeneratingBox),
+}
+
+#[derive(Clone, Copy, Eq, PartialEq)]
+pub(crate) enum DisplayGeneratingBox {
+ OutsideInside {
+ outside: DisplayOutside,
+ inside: DisplayInside,
+ // list_item: bool,
+ },
+ // Layout-internal display types go here:
+ // https://drafts.csswg.org/css-display-3/#layout-specific-display
+}
+
+pub(crate) trait ComputedValuesExt {
+ fn writing_mode(&self) -> (WritingMode, Direction);
+ fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto>;
+ fn box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto>;
+ fn padding(&self) -> flow_relative::Sides<LengthPercentage>;
+ fn border_width(&self) -> flow_relative::Sides<Length>;
+ fn margin(&self) -> flow_relative::Sides<LengthPercentageOrAuto>;
+}
+
+impl ComputedValuesExt for ComputedValues {
+ fn writing_mode(&self) -> (WritingMode, Direction) {
+ let inherited_box = self.get_inherited_box();
+ let writing_mode = inherited_box.writing_mode;
+ let direction = inherited_box.direction;
+ (writing_mode, direction)
+ }
+
+ #[inline]
+ fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto> {
+ let position = self.get_position();
+ physical::Sides {
+ top: position.top,
+ left: position.left,
+ bottom: position.bottom,
+ right: position.right,
+ }
+ .to_flow_relative(self.writing_mode())
+ }
+
+ #[inline]
+ fn box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto> {
+ let position = self.get_position();
+ physical::Vec2 {
+ x: size_to_length(position.width),
+ y: size_to_length(position.height),
+ }
+ .size_to_flow_relative(self.writing_mode())
+ }
+
+ #[inline]
+ fn padding(&self) -> flow_relative::Sides<LengthPercentage> {
+ let padding = self.get_padding();
+ physical::Sides {
+ top: padding.padding_top.0,
+ left: padding.padding_left.0,
+ bottom: padding.padding_bottom.0,
+ right: padding.padding_right.0,
+ }
+ .to_flow_relative(self.writing_mode())
+ }
+
+ fn border_width(&self) -> flow_relative::Sides<Length> {
+ let border = self.get_border();
+ physical::Sides {
+ top: border.border_top_width.0,
+ left: border.border_left_width.0,
+ bottom: border.border_bottom_width.0,
+ right: border.border_right_width.0,
+ }
+ .to_flow_relative(self.writing_mode())
+ }
+
+ fn margin(&self) -> flow_relative::Sides<LengthPercentageOrAuto> {
+ let margin = self.get_margin();
+ physical::Sides {
+ top: margin.margin_top,
+ left: margin.margin_left,
+ bottom: margin.margin_bottom,
+ right: margin.margin_right,
+ }
+ .to_flow_relative(self.writing_mode())
+ }
+}
+
+impl From<PackedDisplay> for Display {
+ fn from(packed_display: PackedDisplay) -> Self {
+ if packed_display == PackedDisplay::None {
+ return Self::None;
+ }
+ if packed_display == PackedDisplay::Contents {
+ return Self::Contents;
+ }
+ Self::GeneratingBox(DisplayGeneratingBox::OutsideInside {
+ outside: packed_display.outside(),
+ inside: packed_display.inside(),
+ // list_item: packed_display.is_list_item(),
+ })
+ }
+}
+
+fn size_to_length(size: Size) -> LengthPercentageOrAuto {
+ match size {
+ Size::LengthPercentage(length) => LengthPercentageOrAuto::LengthPercentage(length.0),
+ Size::Auto => LengthPercentageOrAuto::Auto,
+ }
+}