mirror of
https://github.com/servo/servo.git
synced 2025-09-07 05:28:21 +01:00
Auto merge of #25957 - pcwalton:layout-2020-atomic-refcell, r=nox
Start using `AtomicRefCell` in layout 2020 as preparation for incremental layout This makes `BlockLevelBox` and `InlineLevelBox` use `AtomicRefCell` for incremental layout, per @nox's suggestion in https://github.com/servo/servo/issues/25168. As part of this, it reworks inline layout to use recursion, per https://github.com/servo/servo/issues/25950. LLVM should be able to optimize this into a loop (though I have not verified this). r? @nox
This commit is contained in:
commit
5bf45b2622
12 changed files with 309 additions and 165 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -166,9 +166,9 @@ checksum = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2"
|
|||
|
||||
[[package]]
|
||||
name = "atomic_refcell"
|
||||
version = "0.1.0"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
|
||||
checksum = "3bc31dce067eab974c815a9deb95f6217806de7b53685d7fc31f8ccf3fb2539f"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
|
|
|
@ -14,7 +14,7 @@ doctest = false
|
|||
|
||||
[dependencies]
|
||||
app_units = "0.7"
|
||||
atomic_refcell = "0.1"
|
||||
atomic_refcell = "0.1.6"
|
||||
canvas_traits = {path = "../canvas_traits"}
|
||||
cssparser = "0.27"
|
||||
embedder_traits = {path = "../embedder_traits"}
|
||||
|
|
69
components/layout_2020/cell.rs
Normal file
69
components/layout_2020/cell.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* 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 atomic_refcell::AtomicRefCell;
|
||||
use serde::{Serialize, Serializer};
|
||||
use servo_arc::Arc;
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
|
||||
pub(crate) struct ArcRefCell<T> {
|
||||
value: Arc<AtomicRefCell<T>>,
|
||||
}
|
||||
|
||||
impl<T> ArcRefCell<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self {
|
||||
value: Arc::new(AtomicRefCell::new(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for ArcRefCell<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
value: self.value.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for ArcRefCell<T>
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
value: Arc::new(AtomicRefCell::new(Default::default())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for ArcRefCell<T> {
|
||||
type Target = AtomicRefCell<T>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for ArcRefCell<T>
|
||||
where
|
||||
T: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.value.fmt(formatter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for ArcRefCell<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.borrow().serialize(serializer)
|
||||
}
|
||||
}
|
|
@ -2,13 +2,14 @@
|
|||
* 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::element_data::{LayoutBox, LayoutDataForElement};
|
||||
use crate::geom::PhysicalSize;
|
||||
use crate::replaced::{CanvasInfo, CanvasSource, ReplacedContent};
|
||||
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOutside};
|
||||
use crate::wrapper::GetRawData;
|
||||
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
|
||||
use atomic_refcell::AtomicRefMut;
|
||||
use html5ever::LocalName;
|
||||
use net_traits::image::base::Image as NetImage;
|
||||
use script_layout_interface::wrapper_traits::{
|
||||
|
@ -317,12 +318,12 @@ where
|
|||
}
|
||||
|
||||
pub struct BoxSlot<'dom> {
|
||||
slot: Option<ServoArc<AtomicRefCell<Option<LayoutBox>>>>,
|
||||
slot: Option<ArcRefCell<Option<LayoutBox>>>,
|
||||
marker: marker<&'dom ()>,
|
||||
}
|
||||
|
||||
impl BoxSlot<'_> {
|
||||
pub(crate) fn new(slot: ServoArc<AtomicRefCell<Option<LayoutBox>>>) -> Self {
|
||||
pub(crate) fn new(slot: ArcRefCell<Option<LayoutBox>>) -> Self {
|
||||
*slot.borrow_mut() = None;
|
||||
let slot = Some(slot);
|
||||
Self { slot, marker }
|
||||
|
|
|
@ -2,25 +2,24 @@
|
|||
* 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::flow::inline::InlineLevelBox;
|
||||
use crate::flow::BlockLevelBox;
|
||||
use atomic_refcell::AtomicRefCell;
|
||||
use servo_arc::Arc;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LayoutDataForElement {
|
||||
pub(super) self_box: Arc<AtomicRefCell<Option<LayoutBox>>>,
|
||||
pub(super) self_box: ArcRefCell<Option<LayoutBox>>,
|
||||
pub(super) pseudo_elements: Option<Box<PseudoElementBoxes>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(super) struct PseudoElementBoxes {
|
||||
pub before: Arc<AtomicRefCell<Option<LayoutBox>>>,
|
||||
pub after: Arc<AtomicRefCell<Option<LayoutBox>>>,
|
||||
pub before: ArcRefCell<Option<LayoutBox>>,
|
||||
pub after: ArcRefCell<Option<LayoutBox>>,
|
||||
}
|
||||
|
||||
pub(super) enum LayoutBox {
|
||||
DisplayContents,
|
||||
BlockLevel(Arc<BlockLevelBox>),
|
||||
InlineLevel(Arc<InlineLevelBox>),
|
||||
BlockLevel(ArcRefCell<BlockLevelBox>),
|
||||
InlineLevel(ArcRefCell<InlineLevelBox>),
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::cell::ArcRefCell;
|
||||
use crate::context::LayoutContext;
|
||||
use crate::dom_traversal::{BoxSlot, Contents, NodeExt, NonReplacedContents, TraversalHandler};
|
||||
use crate::element_data::LayoutBox;
|
||||
|
@ -282,54 +283,48 @@ where
|
|||
// context with the parent style of that builder.
|
||||
let inlines = self.current_inline_level_boxes();
|
||||
|
||||
fn last_text(inlines: &mut [Arc<InlineLevelBox>]) -> Option<&mut String> {
|
||||
let last = inlines.last_mut()?;
|
||||
if let InlineLevelBox::TextRun(_) = &**last {
|
||||
// We never clone text run boxes, so the refcount is 1 and unwrap succeeds:
|
||||
let last = Arc::get_mut(last).unwrap();
|
||||
if let InlineLevelBox::TextRun(TextRun { text, .. }) = last {
|
||||
Some(text)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_text_run_contents;
|
||||
let output;
|
||||
if let Some(text) = last_text(inlines) {
|
||||
// Append to the existing text run
|
||||
new_text_run_contents = None;
|
||||
output = text;
|
||||
} else {
|
||||
new_text_run_contents = Some(String::new());
|
||||
output = new_text_run_contents.as_mut().unwrap();
|
||||
}
|
||||
|
||||
if leading_whitespace {
|
||||
output.push(' ')
|
||||
}
|
||||
loop {
|
||||
if let Some(i) = input.bytes().position(|b| b.is_ascii_whitespace()) {
|
||||
let (non_whitespace, rest) = input.split_at(i);
|
||||
output.push_str(non_whitespace);
|
||||
output.push(' ');
|
||||
if let Some(i) = rest.bytes().position(|b| !b.is_ascii_whitespace()) {
|
||||
input = &rest[i..];
|
||||
{
|
||||
let mut last_box = inlines.last_mut().map(|last| last.borrow_mut());
|
||||
let last_text = last_box.as_mut().and_then(|last| match &mut **last {
|
||||
InlineLevelBox::TextRun(last) => Some(&mut last.text),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
if let Some(text) = last_text {
|
||||
// Append to the existing text run
|
||||
new_text_run_contents = None;
|
||||
output = text;
|
||||
} else {
|
||||
new_text_run_contents = Some(String::new());
|
||||
output = new_text_run_contents.as_mut().unwrap();
|
||||
}
|
||||
|
||||
if leading_whitespace {
|
||||
output.push(' ')
|
||||
}
|
||||
loop {
|
||||
if let Some(i) = input.bytes().position(|b| b.is_ascii_whitespace()) {
|
||||
let (non_whitespace, rest) = input.split_at(i);
|
||||
output.push_str(non_whitespace);
|
||||
output.push(' ');
|
||||
if let Some(i) = rest.bytes().position(|b| !b.is_ascii_whitespace()) {
|
||||
input = &rest[i..];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
output.push_str(input);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
output.push_str(input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(text) = new_text_run_contents {
|
||||
let parent_style = parent_style.clone();
|
||||
inlines.push(Arc::new(InlineLevelBox::TextRun(TextRun {
|
||||
inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun {
|
||||
tag: node.as_opaque(),
|
||||
parent_style,
|
||||
text,
|
||||
|
@ -353,29 +348,53 @@ where
|
|||
if !text.starts_with(|c: char| c.is_ascii_whitespace()) {
|
||||
return (false, text);
|
||||
}
|
||||
let mut inline_level_boxes = self.current_inline_level_boxes().iter().rev();
|
||||
let mut stack = Vec::new();
|
||||
let preserved = loop {
|
||||
match inline_level_boxes.next().map(|b| &**b) {
|
||||
Some(InlineLevelBox::TextRun(r)) => break !r.text.ends_with(' '),
|
||||
Some(InlineLevelBox::Atomic { .. }) => break false,
|
||||
Some(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(_)) |
|
||||
Some(InlineLevelBox::OutOfFlowFloatBox(_)) => {},
|
||||
Some(InlineLevelBox::InlineBox(b)) => {
|
||||
stack.push(inline_level_boxes);
|
||||
inline_level_boxes = b.children.iter().rev()
|
||||
},
|
||||
None => {
|
||||
if let Some(iter) = stack.pop() {
|
||||
inline_level_boxes = iter
|
||||
} else {
|
||||
break false; // Paragraph start
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
let preserved = match whitespace_is_preserved(self.current_inline_level_boxes()) {
|
||||
WhitespacePreservedResult::Unknown => {
|
||||
// Paragraph start.
|
||||
false
|
||||
},
|
||||
WhitespacePreservedResult::NotPreserved => false,
|
||||
WhitespacePreservedResult::Preserved => true,
|
||||
};
|
||||
|
||||
let text = text.trim_start_matches(|c: char| c.is_ascii_whitespace());
|
||||
(preserved, text)
|
||||
return (preserved, text);
|
||||
|
||||
fn whitespace_is_preserved(
|
||||
inline_level_boxes: &[ArcRefCell<InlineLevelBox>],
|
||||
) -> WhitespacePreservedResult {
|
||||
for inline_level_box in inline_level_boxes.iter().rev() {
|
||||
match *inline_level_box.borrow() {
|
||||
InlineLevelBox::TextRun(ref r) => {
|
||||
if r.text.ends_with(' ') {
|
||||
return WhitespacePreservedResult::NotPreserved;
|
||||
}
|
||||
return WhitespacePreservedResult::Preserved;
|
||||
},
|
||||
InlineLevelBox::Atomic { .. } => {
|
||||
return WhitespacePreservedResult::NotPreserved;
|
||||
},
|
||||
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(_) |
|
||||
InlineLevelBox::OutOfFlowFloatBox(_) => {},
|
||||
InlineLevelBox::InlineBox(ref b) => {
|
||||
match whitespace_is_preserved(&b.children) {
|
||||
WhitespacePreservedResult::Unknown => {},
|
||||
result => return result,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
WhitespacePreservedResult::Unknown
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum WhitespacePreservedResult {
|
||||
Preserved,
|
||||
NotPreserved,
|
||||
Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_inline_level_element(
|
||||
|
@ -384,7 +403,7 @@ where
|
|||
style: &Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents,
|
||||
) -> Arc<InlineLevelBox> {
|
||||
) -> ArcRefCell<InlineLevelBox> {
|
||||
let box_ = if display_inside == DisplayInside::Flow && !contents.is_replaced() {
|
||||
// We found un inline box.
|
||||
// Whatever happened before, all we need to do before recurring
|
||||
|
@ -410,9 +429,9 @@ where
|
|||
.pop()
|
||||
.expect("no ongoing inline level box found");
|
||||
inline_box.last_fragment = true;
|
||||
Arc::new(InlineLevelBox::InlineBox(inline_box))
|
||||
ArcRefCell::new(InlineLevelBox::InlineBox(inline_box))
|
||||
} else {
|
||||
Arc::new(InlineLevelBox::Atomic(
|
||||
ArcRefCell::new(InlineLevelBox::Atomic(
|
||||
IndependentFormattingContext::construct(
|
||||
self.context,
|
||||
node,
|
||||
|
@ -466,13 +485,13 @@ where
|
|||
for mut fragmented_parent_inline_box in fragmented_inline_boxes {
|
||||
fragmented_parent_inline_box
|
||||
.children
|
||||
.push(Arc::new(fragmented_inline));
|
||||
.push(ArcRefCell::new(fragmented_inline));
|
||||
fragmented_inline = InlineLevelBox::InlineBox(fragmented_parent_inline_box);
|
||||
}
|
||||
|
||||
self.ongoing_inline_formatting_context
|
||||
.inline_level_boxes
|
||||
.push(Arc::new(fragmented_inline));
|
||||
.push(ArcRefCell::new(fragmented_inline));
|
||||
}
|
||||
|
||||
// We found a block level element, so the ongoing inline formatting
|
||||
|
@ -525,7 +544,7 @@ where
|
|||
kind,
|
||||
});
|
||||
} else {
|
||||
let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(
|
||||
let box_ = ArcRefCell::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
|
||||
AbsolutelyPositionedBox::construct(
|
||||
self.context,
|
||||
node,
|
||||
|
@ -533,7 +552,7 @@ where
|
|||
display_inside,
|
||||
contents,
|
||||
),
|
||||
));
|
||||
)));
|
||||
self.current_inline_level_boxes().push(box_.clone());
|
||||
box_slot.set(LayoutBox::InlineLevel(box_))
|
||||
}
|
||||
|
@ -561,7 +580,7 @@ where
|
|||
kind,
|
||||
});
|
||||
} else {
|
||||
let box_ = Arc::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct(
|
||||
let box_ = ArcRefCell::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct(
|
||||
self.context,
|
||||
node,
|
||||
style,
|
||||
|
@ -610,7 +629,7 @@ where
|
|||
});
|
||||
}
|
||||
|
||||
fn current_inline_level_boxes(&mut self) -> &mut Vec<Arc<InlineLevelBox>> {
|
||||
fn current_inline_level_boxes(&mut self) -> &mut Vec<ArcRefCell<InlineLevelBox>> {
|
||||
match self.ongoing_inline_boxes_stack.last_mut() {
|
||||
Some(last) => &mut last.children,
|
||||
None => &mut self.ongoing_inline_formatting_context.inline_level_boxes,
|
||||
|
@ -634,7 +653,7 @@ where
|
|||
self,
|
||||
context: &LayoutContext,
|
||||
max_assign_in_flow_outer_content_sizes_to: Option<&mut ContentSizes>,
|
||||
) -> (Arc<BlockLevelBox>, ContainsFloats) {
|
||||
) -> (ArcRefCell<BlockLevelBox>, ContainsFloats) {
|
||||
let node = self.node;
|
||||
let style = self.style;
|
||||
let (block_level_box, contains_floats) = match self.kind {
|
||||
|
@ -651,7 +670,7 @@ where
|
|||
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
|
||||
to.max_assign(&box_content_sizes.outer_inline(&style))
|
||||
}
|
||||
let block_level_box = Arc::new(BlockLevelBox::SameFormattingContextBlock {
|
||||
let block_level_box = ArcRefCell::new(BlockLevelBox::SameFormattingContextBlock {
|
||||
tag: node.as_opaque(),
|
||||
contents,
|
||||
style,
|
||||
|
@ -678,7 +697,7 @@ where
|
|||
to.max_assign(&contents.content_sizes.outer_inline(&contents.style))
|
||||
}
|
||||
(
|
||||
Arc::new(BlockLevelBox::Independent(contents)),
|
||||
ArcRefCell::new(BlockLevelBox::Independent(contents)),
|
||||
ContainsFloats::No,
|
||||
)
|
||||
},
|
||||
|
@ -686,22 +705,23 @@ where
|
|||
display_inside,
|
||||
contents,
|
||||
} => {
|
||||
let block_level_box = Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
|
||||
AbsolutelyPositionedBox::construct(
|
||||
context,
|
||||
node,
|
||||
style,
|
||||
display_inside,
|
||||
contents,
|
||||
),
|
||||
));
|
||||
let block_level_box =
|
||||
ArcRefCell::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
|
||||
AbsolutelyPositionedBox::construct(
|
||||
context,
|
||||
node,
|
||||
style,
|
||||
display_inside,
|
||||
contents,
|
||||
),
|
||||
)));
|
||||
(block_level_box, ContainsFloats::No)
|
||||
},
|
||||
BlockLevelCreator::OutOfFlowFloatBox {
|
||||
display_inside,
|
||||
contents,
|
||||
} => {
|
||||
let block_level_box = Arc::new(BlockLevelBox::OutOfFlowFloatBox(
|
||||
let block_level_box = ArcRefCell::new(BlockLevelBox::OutOfFlowFloatBox(
|
||||
FloatBox::construct(context, node, style, display_inside, contents),
|
||||
));
|
||||
(block_level_box, ContainsFloats::Yes)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::cell::ArcRefCell;
|
||||
use crate::context::LayoutContext;
|
||||
use crate::flow::float::FloatBox;
|
||||
use crate::flow::FlowLayout;
|
||||
|
@ -27,14 +28,14 @@ use webrender_api::FontInstanceKey;
|
|||
|
||||
#[derive(Debug, Default, Serialize)]
|
||||
pub(crate) struct InlineFormattingContext {
|
||||
pub(super) inline_level_boxes: Vec<Arc<InlineLevelBox>>,
|
||||
pub(super) inline_level_boxes: Vec<ArcRefCell<InlineLevelBox>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub(crate) enum InlineLevelBox {
|
||||
InlineBox(InlineBox),
|
||||
TextRun(TextRun),
|
||||
OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox),
|
||||
OutOfFlowAbsolutelyPositionedBox(Arc<AbsolutelyPositionedBox>),
|
||||
OutOfFlowFloatBox(FloatBox),
|
||||
Atomic(IndependentFormattingContext),
|
||||
}
|
||||
|
@ -46,7 +47,7 @@ pub(crate) struct InlineBox {
|
|||
pub style: Arc<ComputedValues>,
|
||||
pub first_fragment: bool,
|
||||
pub last_fragment: bool,
|
||||
pub children: Vec<Arc<InlineLevelBox>>,
|
||||
pub children: Vec<ArcRefCell<InlineLevelBox>>,
|
||||
}
|
||||
|
||||
/// https://www.w3.org/TR/css-display-3/#css-text-run
|
||||
|
@ -59,7 +60,7 @@ pub(crate) struct TextRun {
|
|||
}
|
||||
|
||||
struct InlineNestingLevelState<'box_tree> {
|
||||
remaining_boxes: std::slice::Iter<'box_tree, Arc<InlineLevelBox>>,
|
||||
remaining_boxes: InlineBoxChildIter<'box_tree>,
|
||||
fragments_so_far: Vec<Fragment>,
|
||||
inline_start: Length,
|
||||
max_block_size_of_fragments_so_far: Length,
|
||||
|
@ -77,7 +78,7 @@ struct PartialInlineBoxFragment<'box_tree> {
|
|||
}
|
||||
|
||||
struct InlineFormattingContextState<'box_tree, 'a, 'b> {
|
||||
positioning_context: &'a mut PositioningContext<'box_tree>,
|
||||
positioning_context: &'a mut PositioningContext,
|
||||
containing_block: &'b ContainingBlock<'b>,
|
||||
lines: Lines,
|
||||
inline_position: Length,
|
||||
|
@ -105,10 +106,10 @@ impl InlineFormattingContext {
|
|||
fn traverse(
|
||||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
inline_level_boxes: &[Arc<InlineLevelBox>],
|
||||
inline_level_boxes: &[ArcRefCell<InlineLevelBox>],
|
||||
) {
|
||||
for inline_level_box in inline_level_boxes {
|
||||
match &**inline_level_box {
|
||||
match &*inline_level_box.borrow() {
|
||||
InlineLevelBox::InlineBox(inline_box) => {
|
||||
let padding = inline_box.style.padding();
|
||||
let border = inline_box.style.border_width();
|
||||
|
@ -204,10 +205,10 @@ impl InlineFormattingContext {
|
|||
computation.paragraph
|
||||
}
|
||||
|
||||
pub(super) fn layout<'a>(
|
||||
&'a self,
|
||||
pub(super) fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
positioning_context: &mut PositioningContext<'a>,
|
||||
positioning_context: &mut PositioningContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
) -> FlowLayout {
|
||||
|
@ -221,7 +222,7 @@ impl InlineFormattingContext {
|
|||
},
|
||||
inline_position: Length::zero(),
|
||||
current_nesting_level: InlineNestingLevelState {
|
||||
remaining_boxes: self.inline_level_boxes.iter(),
|
||||
remaining_boxes: InlineBoxChildIter::from_formatting_context(self),
|
||||
fragments_so_far: Vec::with_capacity(self.inline_level_boxes.len()),
|
||||
inline_start: Length::zero(),
|
||||
max_block_size_of_fragments_so_far: Length::zero(),
|
||||
|
@ -229,9 +230,9 @@ impl InlineFormattingContext {
|
|||
};
|
||||
loop {
|
||||
if let Some(child) = ifc.current_nesting_level.remaining_boxes.next() {
|
||||
match &**child {
|
||||
match &*child.borrow() {
|
||||
InlineLevelBox::InlineBox(inline) => {
|
||||
let partial = inline.start_layout(&mut ifc);
|
||||
let partial = inline.start_layout(child.clone(), &mut ifc);
|
||||
ifc.partial_inline_boxes_stack.push(partial)
|
||||
},
|
||||
InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc),
|
||||
|
@ -256,7 +257,8 @@ impl InlineFormattingContext {
|
|||
panic!("display:none does not generate an abspos box")
|
||||
},
|
||||
};
|
||||
let hoisted_fragment = box_.to_hoisted(initial_start_corner, tree_rank);
|
||||
let hoisted_fragment =
|
||||
box_.clone().to_hoisted(initial_start_corner, tree_rank);
|
||||
let hoisted_fragment_id = hoisted_fragment.fragment_id;
|
||||
ifc.positioning_context.push(hoisted_fragment);
|
||||
ifc.lines
|
||||
|
@ -364,7 +366,8 @@ impl Lines {
|
|||
|
||||
impl InlineBox {
|
||||
fn start_layout<'box_tree>(
|
||||
&'box_tree self,
|
||||
&self,
|
||||
this_inline_level_box: ArcRefCell<InlineLevelBox>,
|
||||
ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>,
|
||||
) -> PartialInlineBoxFragment<'box_tree> {
|
||||
let style = self.style.clone();
|
||||
|
@ -400,7 +403,9 @@ impl InlineBox {
|
|||
parent_nesting_level: std::mem::replace(
|
||||
&mut ifc.current_nesting_level,
|
||||
InlineNestingLevelState {
|
||||
remaining_boxes: self.children.iter(),
|
||||
remaining_boxes: InlineBoxChildIter::from_inline_level_box(
|
||||
this_inline_level_box,
|
||||
),
|
||||
fragments_so_far: Vec::with_capacity(self.children.len()),
|
||||
inline_start: ifc.inline_position,
|
||||
max_block_size_of_fragments_so_far: Length::zero(),
|
||||
|
@ -460,10 +465,10 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
|
|||
}
|
||||
}
|
||||
|
||||
fn layout_atomic<'box_tree>(
|
||||
fn layout_atomic(
|
||||
layout_context: &LayoutContext,
|
||||
ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>,
|
||||
atomic: &'box_tree IndependentFormattingContext,
|
||||
ifc: &mut InlineFormattingContextState,
|
||||
atomic: &IndependentFormattingContext,
|
||||
) {
|
||||
let cbis = ifc.containing_block.inline_size;
|
||||
let padding = atomic.style.padding().percentages_relative_to(cbis);
|
||||
|
@ -758,3 +763,54 @@ impl TextRun {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum InlineBoxChildIter<'box_tree> {
|
||||
InlineFormattingContext(std::slice::Iter<'box_tree, ArcRefCell<InlineLevelBox>>),
|
||||
InlineBox {
|
||||
inline_level_box: ArcRefCell<InlineLevelBox>,
|
||||
child_index: usize,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'box_tree> InlineBoxChildIter<'box_tree> {
|
||||
fn from_formatting_context(
|
||||
inline_formatting_context: &'box_tree InlineFormattingContext,
|
||||
) -> InlineBoxChildIter<'box_tree> {
|
||||
InlineBoxChildIter::InlineFormattingContext(
|
||||
inline_formatting_context.inline_level_boxes.iter(),
|
||||
)
|
||||
}
|
||||
|
||||
fn from_inline_level_box(
|
||||
inline_level_box: ArcRefCell<InlineLevelBox>,
|
||||
) -> InlineBoxChildIter<'box_tree> {
|
||||
InlineBoxChildIter::InlineBox {
|
||||
inline_level_box,
|
||||
child_index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'box_tree> Iterator for InlineBoxChildIter<'box_tree> {
|
||||
type Item = ArcRefCell<InlineLevelBox>;
|
||||
fn next(&mut self) -> Option<ArcRefCell<InlineLevelBox>> {
|
||||
match *self {
|
||||
InlineBoxChildIter::InlineFormattingContext(ref mut iter) => iter.next().cloned(),
|
||||
InlineBoxChildIter::InlineBox {
|
||||
ref inline_level_box,
|
||||
ref mut child_index,
|
||||
} => match *inline_level_box.borrow() {
|
||||
InlineLevelBox::InlineBox(ref inline_box) => {
|
||||
if *child_index >= inline_box.children.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let kid = inline_box.children[*child_index].clone();
|
||||
*child_index += 1;
|
||||
Some(kid)
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
//! Flow layout, also known as block-and-inline layout.
|
||||
|
||||
use crate::cell::ArcRefCell;
|
||||
use crate::context::LayoutContext;
|
||||
use crate::flow::float::{FloatBox, FloatContext};
|
||||
use crate::flow::inline::InlineFormattingContext;
|
||||
|
@ -38,7 +39,7 @@ pub(crate) struct BlockFormattingContext {
|
|||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub(crate) enum BlockContainer {
|
||||
BlockLevelBoxes(Vec<Arc<BlockLevelBox>>),
|
||||
BlockLevelBoxes(Vec<ArcRefCell<BlockLevelBox>>),
|
||||
InlineFormattingContext(InlineFormattingContext),
|
||||
}
|
||||
|
||||
|
@ -50,7 +51,7 @@ pub(crate) enum BlockLevelBox {
|
|||
style: Arc<ComputedValues>,
|
||||
contents: BlockContainer,
|
||||
},
|
||||
OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox),
|
||||
OutOfFlowAbsolutelyPositionedBox(Arc<AbsolutelyPositionedBox>),
|
||||
OutOfFlowFloatBox(FloatBox),
|
||||
Independent(IndependentFormattingContext),
|
||||
}
|
||||
|
@ -65,10 +66,10 @@ struct FlowLayout {
|
|||
struct CollapsibleWithParentStartMargin(bool);
|
||||
|
||||
impl BlockFormattingContext {
|
||||
pub(super) fn layout<'a>(
|
||||
&'a self,
|
||||
pub(super) fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
positioning_context: &mut PositioningContext<'a>,
|
||||
positioning_context: &mut PositioningContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
) -> IndependentLayout {
|
||||
|
@ -101,10 +102,10 @@ impl BlockFormattingContext {
|
|||
}
|
||||
|
||||
impl BlockContainer {
|
||||
fn layout<'a>(
|
||||
&'a self,
|
||||
fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
positioning_context: &mut PositioningContext<'a>,
|
||||
positioning_context: &mut PositioningContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
float_context: Option<&mut FloatContext>,
|
||||
|
@ -130,10 +131,10 @@ impl BlockContainer {
|
|||
}
|
||||
}
|
||||
|
||||
fn layout_block_level_children<'a>(
|
||||
fn layout_block_level_children(
|
||||
layout_context: &LayoutContext,
|
||||
positioning_context: &mut PositioningContext<'a>,
|
||||
child_boxes: &'a [Arc<BlockLevelBox>],
|
||||
positioning_context: &mut PositioningContext,
|
||||
child_boxes: &[ArcRefCell<BlockLevelBox>],
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
mut float_context: Option<&mut FloatContext>,
|
||||
|
@ -204,7 +205,7 @@ fn layout_block_level_children<'a>(
|
|||
.iter()
|
||||
.enumerate()
|
||||
.map(|(tree_rank, box_)| {
|
||||
let mut fragment = box_.layout(
|
||||
let mut fragment = box_.borrow().layout(
|
||||
layout_context,
|
||||
positioning_context,
|
||||
containing_block,
|
||||
|
@ -224,7 +225,7 @@ fn layout_block_level_children<'a>(
|
|||
.mapfold_reduce_into(
|
||||
positioning_context,
|
||||
|positioning_context, (tree_rank, box_)| {
|
||||
box_.layout(
|
||||
box_.borrow().layout(
|
||||
layout_context,
|
||||
positioning_context,
|
||||
containing_block,
|
||||
|
@ -256,10 +257,10 @@ fn layout_block_level_children<'a>(
|
|||
}
|
||||
|
||||
impl BlockLevelBox {
|
||||
fn layout<'a>(
|
||||
&'a self,
|
||||
fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
positioning_context: &mut PositioningContext<'a>,
|
||||
positioning_context: &mut PositioningContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
float_context: Option<&mut FloatContext>,
|
||||
|
@ -314,7 +315,7 @@ impl BlockLevelBox {
|
|||
))
|
||||
},
|
||||
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
|
||||
let hoisted_fragment = box_.to_hoisted(Vec2::zero(), tree_rank);
|
||||
let hoisted_fragment = box_.clone().to_hoisted(Vec2::zero(), tree_rank);
|
||||
let hoisted_fragment_id = hoisted_fragment.fragment_id.clone();
|
||||
positioning_context.push(hoisted_fragment);
|
||||
Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment(
|
||||
|
@ -338,13 +339,13 @@ enum NonReplacedContents<'a> {
|
|||
|
||||
/// https://drafts.csswg.org/css2/visudet.html#blockwidth
|
||||
/// https://drafts.csswg.org/css2/visudet.html#normal-block
|
||||
fn layout_in_flow_non_replaced_block_level<'a>(
|
||||
fn layout_in_flow_non_replaced_block_level(
|
||||
layout_context: &LayoutContext,
|
||||
positioning_context: &mut PositioningContext<'a>,
|
||||
positioning_context: &mut PositioningContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tag: OpaqueNode,
|
||||
style: &Arc<ComputedValues>,
|
||||
block_level_kind: NonReplacedContents<'a>,
|
||||
block_level_kind: NonReplacedContents,
|
||||
tree_rank: usize,
|
||||
float_context: Option<&mut FloatContext>,
|
||||
) -> BoxFragment {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::cell::ArcRefCell;
|
||||
use crate::context::LayoutContext;
|
||||
use crate::display_list::stacking_context::{
|
||||
ContainingBlock, ContainingBlockInfo, StackingContext, StackingContextBuildMode,
|
||||
|
@ -62,7 +63,7 @@ impl BoxTreeRoot {
|
|||
fn construct_for_root_element<'dom>(
|
||||
context: &LayoutContext,
|
||||
root_element: impl NodeExt<'dom>,
|
||||
) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
|
||||
) -> (ContainsFloats, Vec<ArcRefCell<BlockLevelBox>>) {
|
||||
let style = root_element.style(context);
|
||||
let replaced = ReplacedContent::for_element(root_element);
|
||||
let box_style = style.get_box();
|
||||
|
@ -83,27 +84,29 @@ fn construct_for_root_element<'dom>(
|
|||
if box_style.position.is_absolutely_positioned() {
|
||||
(
|
||||
ContainsFloats::No,
|
||||
vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
|
||||
AbsolutelyPositionedBox::construct(
|
||||
context,
|
||||
root_element,
|
||||
style,
|
||||
display_inside,
|
||||
contents,
|
||||
),
|
||||
))],
|
||||
vec![ArcRefCell::new(
|
||||
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
|
||||
AbsolutelyPositionedBox::construct(
|
||||
context,
|
||||
root_element,
|
||||
style,
|
||||
display_inside,
|
||||
contents,
|
||||
),
|
||||
)),
|
||||
)],
|
||||
)
|
||||
} else if box_style.float.is_floating() {
|
||||
(
|
||||
ContainsFloats::Yes,
|
||||
vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(
|
||||
vec![ArcRefCell::new(BlockLevelBox::OutOfFlowFloatBox(
|
||||
FloatBox::construct(context, root_element, style, display_inside, contents),
|
||||
))],
|
||||
)
|
||||
} else {
|
||||
(
|
||||
ContainsFloats::No,
|
||||
vec![Arc::new(BlockLevelBox::Independent(
|
||||
vec![ArcRefCell::new(BlockLevelBox::Independent(
|
||||
IndependentFormattingContext::construct(
|
||||
context,
|
||||
root_element,
|
||||
|
|
|
@ -104,11 +104,11 @@ impl IndependentFormattingContext {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> NonReplacedIFC<'a> {
|
||||
impl NonReplacedIFC<'_> {
|
||||
pub fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
positioning_context: &mut PositioningContext<'a>,
|
||||
positioning_context: &mut PositioningContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
) -> IndependentLayout {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -10,6 +11,7 @@ extern crate log;
|
|||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
||||
mod cell;
|
||||
pub mod context;
|
||||
pub mod data;
|
||||
pub mod display_list;
|
||||
|
|
|
@ -36,19 +36,18 @@ pub(crate) struct AbsolutelyPositionedBox {
|
|||
pub contents: IndependentFormattingContext,
|
||||
}
|
||||
|
||||
pub(crate) struct PositioningContext<'box_tree> {
|
||||
for_nearest_positioned_ancestor: Option<Vec<HoistedAbsolutelyPositionedBox<'box_tree>>>,
|
||||
pub(crate) struct PositioningContext {
|
||||
for_nearest_positioned_ancestor: Option<Vec<HoistedAbsolutelyPositionedBox>>,
|
||||
|
||||
// For nearest `containing block for all descendants` as defined by the CSS transforms
|
||||
// spec.
|
||||
// https://www.w3.org/TR/css-transforms-1/#containing-block-for-all-descendants
|
||||
for_nearest_containing_block_for_all_descendants:
|
||||
Vec<HoistedAbsolutelyPositionedBox<'box_tree>>,
|
||||
for_nearest_containing_block_for_all_descendants: Vec<HoistedAbsolutelyPositionedBox>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct HoistedAbsolutelyPositionedBox<'box_tree> {
|
||||
absolutely_positioned_box: &'box_tree AbsolutelyPositionedBox,
|
||||
pub(crate) struct HoistedAbsolutelyPositionedBox {
|
||||
absolutely_positioned_box: Arc<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
|
||||
|
@ -110,7 +109,7 @@ impl AbsolutelyPositionedBox {
|
|||
}
|
||||
|
||||
pub(crate) fn to_hoisted(
|
||||
&self,
|
||||
self: Arc<Self>,
|
||||
initial_start_corner: Vec2<Length>,
|
||||
tree_rank: usize,
|
||||
) -> HoistedAbsolutelyPositionedBox {
|
||||
|
@ -150,7 +149,7 @@ impl AbsolutelyPositionedBox {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'box_tree> PositioningContext<'box_tree> {
|
||||
impl PositioningContext {
|
||||
pub(crate) fn new_for_containing_block_for_all_descendants() -> Self {
|
||||
Self {
|
||||
for_nearest_positioned_ancestor: None,
|
||||
|
@ -220,9 +219,7 @@ impl<'box_tree> PositioningContext<'box_tree> {
|
|||
fn create_and_layout_positioned(
|
||||
layout_context: &LayoutContext,
|
||||
style: &ComputedValues,
|
||||
for_nearest_containing_block_for_all_descendants: &mut Vec<
|
||||
HoistedAbsolutelyPositionedBox<'box_tree>,
|
||||
>,
|
||||
for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>,
|
||||
fragment_layout_fn: impl FnOnce(&mut Self) -> BoxFragment,
|
||||
) -> BoxFragment {
|
||||
if style.establishes_containing_block_for_all_descendants() {
|
||||
|
@ -296,7 +293,7 @@ impl<'box_tree> PositioningContext<'box_tree> {
|
|||
new_fragment
|
||||
}
|
||||
|
||||
pub(crate) fn push(&mut self, box_: HoistedAbsolutelyPositionedBox<'box_tree>) {
|
||||
pub(crate) fn push(&mut self, box_: HoistedAbsolutelyPositionedBox) {
|
||||
if let Some(nearest) = &mut self.for_nearest_positioned_ancestor {
|
||||
match box_
|
||||
.absolutely_positioned_box
|
||||
|
@ -412,14 +409,12 @@ impl<'box_tree> PositioningContext<'box_tree> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
|
||||
impl HoistedAbsolutelyPositionedBox {
|
||||
pub(crate) fn layout_many(
|
||||
layout_context: &LayoutContext,
|
||||
boxes: &[Self],
|
||||
fragments: &mut Vec<Fragment>,
|
||||
for_nearest_containing_block_for_all_descendants: &mut Vec<
|
||||
HoistedAbsolutelyPositionedBox<'box_tree>,
|
||||
>,
|
||||
for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>,
|
||||
containing_block: &DefiniteContainingBlock,
|
||||
) {
|
||||
if layout_context.use_rayon {
|
||||
|
@ -449,9 +444,7 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
|
|||
pub(crate) fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
for_nearest_containing_block_for_all_descendants: &mut Vec<
|
||||
HoistedAbsolutelyPositionedBox<'box_tree>,
|
||||
>,
|
||||
for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>,
|
||||
containing_block: &DefiniteContainingBlock,
|
||||
) -> BoxFragment {
|
||||
let style = &self.absolutely_positioned_box.contents.style;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue