Auto merge of #26805 - mrobinson:add-pseudo-tag-to-layout-2020, r=SimonSapin

layout_2020: Tag fragments with their pseudo content type

This will allow us to answer queries and properly handle animations in
the future for fragments generated for pseudo content.

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] There are tests for these changes

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
bors-servo 2020-06-06 13:26:19 -04:00 committed by GitHub
commit 0645d8c36d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 271 additions and 265 deletions

View file

@ -4,7 +4,7 @@
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::display_list::conversions::ToWebRender; use crate::display_list::conversions::ToWebRender;
use crate::fragments::{BoxFragment, Fragment, TextFragment}; use crate::fragments::{BoxFragment, Fragment, Tag, TextFragment};
use crate::geom::{PhysicalPoint, PhysicalRect}; use crate::geom::{PhysicalPoint, PhysicalRect};
use crate::replaced::IntrinsicSizes; use crate::replaced::IntrinsicSizes;
use crate::style_ext::ComputedValuesExt; use crate::style_ext::ComputedValuesExt;
@ -348,7 +348,7 @@ impl<'a> BuilderForBoxFragment<'a> {
} }
fn build_background(&mut self, builder: &mut DisplayListBuilder) { fn build_background(&mut self, builder: &mut DisplayListBuilder) {
if self.fragment.tag == builder.element_for_canvas_background { if self.fragment.tag.node() == builder.element_for_canvas_background {
// This background is already painted for the canvas, dont paint it again here. // This background is already painted for the canvas, dont paint it again here.
return; return;
} }
@ -405,7 +405,7 @@ impl<'a> BuilderForBoxFragment<'a> {
let (width, height, key) = match image_url.url() { let (width, height, key) = match image_url.url() {
Some(url) => { Some(url) => {
match builder.context.get_webrender_image_for_url( match builder.context.get_webrender_image_for_url(
self.fragment.tag, self.fragment.tag.node(),
url.clone(), url.clone(),
UsePlaceholder::No, UsePlaceholder::No,
) { ) {
@ -541,7 +541,7 @@ fn glyphs(
glyphs glyphs
} }
fn hit_info(style: &ComputedValues, tag: OpaqueNode, auto_cursor: Cursor) -> HitInfo { fn hit_info(style: &ComputedValues, tag: Tag, auto_cursor: Cursor) -> HitInfo {
use style::computed_values::pointer_events::T as PointerEvents; use style::computed_values::pointer_events::T as PointerEvents;
let inherited_ui = style.get_inherited_ui(); let inherited_ui = style.get_inherited_ui();
@ -549,7 +549,7 @@ fn hit_info(style: &ComputedValues, tag: OpaqueNode, auto_cursor: Cursor) -> Hit
None None
} else { } else {
let cursor = cursor(inherited_ui.cursor.keyword, auto_cursor); let cursor = cursor(inherited_ui.cursor.keyword, auto_cursor);
Some((tag.0 as u64, cursor as u16)) Some((tag.node().0 as u64, cursor as u16))
} }
} }

View file

@ -11,7 +11,6 @@ use crate::fragments::{
use crate::geom::PhysicalRect; use crate::geom::PhysicalRect;
use crate::style_ext::ComputedValuesExt; use crate::style_ext::ComputedValuesExt;
use euclid::default::Rect; use euclid::default::Rect;
use gfx_traits::{combine_id_with_fragment_type, FragmentType};
use servo_arc::Arc as ServoArc; use servo_arc::Arc as ServoArc;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::mem; use std::mem;
@ -329,7 +328,7 @@ impl StackingContext {
// The `StackingContextFragment` we found is for the root DOM element: // The `StackingContextFragment` we found is for the root DOM element:
debug_assert_eq!( debug_assert_eq!(
box_fragment.tag, box_fragment.tag.node(),
fragment_tree.canvas_background.root_element fragment_tree.canvas_background.root_element
); );
@ -705,12 +704,10 @@ impl BoxFragment {
let overflow_y = self.style.get_box().overflow_y; let overflow_y = self.style.get_box().overflow_y;
let original_scroll_and_clip_info = builder.current_space_and_clip; let original_scroll_and_clip_info = builder.current_space_and_clip;
if overflow_x != ComputedOverflow::Visible || overflow_y != ComputedOverflow::Visible { if overflow_x != ComputedOverflow::Visible || overflow_y != ComputedOverflow::Visible {
// TODO(mrobinson): We should use the correct fragment type, once we generate let external_id = wr::ExternalScrollId(
// fragments from ::before and ::after generated content selectors. self.tag.to_display_list_fragment_id(),
let id = builder.wr.pipeline_id,
combine_id_with_fragment_type(self.tag.id() as usize, FragmentType::FragmentBody) );
as u64;
let external_id = wr::ExternalScrollId(id, builder.wr.pipeline_id);
let sensitivity = if ComputedOverflow::Hidden == overflow_x && let sensitivity = if ComputedOverflow::Hidden == overflow_x &&
ComputedOverflow::Hidden == overflow_y ComputedOverflow::Hidden == overflow_y

View file

@ -27,11 +27,52 @@ use style::values::generics::counters::Content;
use style::values::generics::counters::ContentItem; use style::values::generics::counters::ContentItem;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub enum WhichPseudoElement { pub(crate) enum WhichPseudoElement {
Before, Before,
After, After,
} }
/// A data structure used to pass and store related layout information together to
/// avoid having to repeat the same arguments in argument lists.
#[derive(Clone)]
pub(crate) struct NodeAndStyleInfo<Node> {
pub node: Node,
pub pseudo_element_type: Option<WhichPseudoElement>,
pub style: ServoArc<ComputedValues>,
}
impl<Node> NodeAndStyleInfo<Node> {
fn new_with_pseudo(
node: Node,
pseudo_element_type: WhichPseudoElement,
style: ServoArc<ComputedValues>,
) -> Self {
Self {
node,
pseudo_element_type: Some(pseudo_element_type),
style,
}
}
pub(crate) fn new(node: Node, style: ServoArc<ComputedValues>) -> Self {
Self {
node,
pseudo_element_type: None,
style,
}
}
}
impl<Node: Clone> NodeAndStyleInfo<Node> {
pub(crate) fn new_replacing_style(&self, style: ServoArc<ComputedValues>) -> Self {
Self {
node: self.node.clone(),
pseudo_element_type: self.pseudo_element_type.clone(),
style,
}
}
}
pub(super) enum Contents { pub(super) enum Contents {
/// Refers to a DOM subtree, plus `::before` and `::after` pseudo-elements. /// Refers to a DOM subtree, plus `::before` and `::after` pseudo-elements.
OfElement, OfElement,
@ -60,18 +101,12 @@ pub(super) trait TraversalHandler<'dom, Node>
where where
Node: 'dom, Node: 'dom,
{ {
fn handle_text( fn handle_text(&mut self, info: &NodeAndStyleInfo<Node>, text: Cow<'dom, str>);
&mut self,
node: Node,
text: Cow<'dom, str>,
parent_style: ServoArc<ComputedValues>,
);
/// Or pseudo-element /// Or pseudo-element
fn handle_element( fn handle_element(
&mut self, &mut self,
node: Node, info: &NodeAndStyleInfo<Node>,
style: ServoArc<ComputedValues>,
display: DisplayGeneratingBox, display: DisplayGeneratingBox,
contents: Contents, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
@ -89,7 +124,8 @@ fn traverse_children_of<'dom, Node>(
for child in iter_child_nodes(parent_element) { for child in iter_child_nodes(parent_element) {
if let Some(contents) = child.as_text() { if let Some(contents) = child.as_text() {
handler.handle_text(child, contents, child.style(context)); let info = NodeAndStyleInfo::new(child, child.style(context));
handler.handle_text(&info, contents);
} else if child.is_element() { } else if child.is_element() {
traverse_element(child, context, handler); traverse_element(child, context, handler);
} }
@ -122,7 +158,8 @@ fn traverse_element<'dom, Node>(
Display::GeneratingBox(display) => { Display::GeneratingBox(display) => {
let contents = replaced.map_or(Contents::OfElement, Contents::Replaced); let contents = replaced.map_or(Contents::OfElement, Contents::Replaced);
let box_slot = element.element_box_slot(); let box_slot = element.element_box_slot();
handler.handle_element(element, style, display, contents, box_slot); let info = NodeAndStyleInfo::new(element, style);
handler.handle_element(&info, display, contents, box_slot);
}, },
} }
} }
@ -136,19 +173,20 @@ fn traverse_pseudo_element<'dom, Node>(
Node: NodeExt<'dom>, Node: NodeExt<'dom>,
{ {
if let Some(style) = pseudo_element_style(which, element, context) { if let Some(style) = pseudo_element_style(which, element, context) {
match Display::from(style.get_box().display) { let info = NodeAndStyleInfo::new_with_pseudo(element, which, style);
match Display::from(info.style.get_box().display) {
Display::None => element.unset_pseudo_element_box(which), Display::None => element.unset_pseudo_element_box(which),
Display::Contents => { Display::Contents => {
let items = generate_pseudo_element_content(&style, element, context); let items = generate_pseudo_element_content(&info.style, element, context);
let box_slot = element.pseudo_element_box_slot(which); let box_slot = element.pseudo_element_box_slot(which);
box_slot.set(LayoutBox::DisplayContents); box_slot.set(LayoutBox::DisplayContents);
traverse_pseudo_element_contents(element, &style, context, handler, items); traverse_pseudo_element_contents(&info, context, handler, items);
}, },
Display::GeneratingBox(display) => { Display::GeneratingBox(display) => {
let items = generate_pseudo_element_content(&style, element, context); let items = generate_pseudo_element_content(&info.style, element, context);
let box_slot = element.pseudo_element_box_slot(which); let box_slot = element.pseudo_element_box_slot(which);
let contents = Contents::OfPseudoElement(items); let contents = Contents::OfPseudoElement(items);
handler.handle_element(element, style, display, contents, box_slot); handler.handle_element(&info, display, contents, box_slot);
}, },
} }
} else { } else {
@ -157,8 +195,7 @@ fn traverse_pseudo_element<'dom, Node>(
} }
fn traverse_pseudo_element_contents<'dom, Node>( fn traverse_pseudo_element_contents<'dom, Node>(
node: Node, info: &NodeAndStyleInfo<Node>,
pseudo_element_style: &ServoArc<ComputedValues>,
context: &LayoutContext, context: &LayoutContext,
handler: &mut impl TraversalHandler<'dom, Node>, handler: &mut impl TraversalHandler<'dom, Node>,
items: Vec<PseudoElementContentItem>, items: Vec<PseudoElementContentItem>,
@ -168,9 +205,7 @@ fn traverse_pseudo_element_contents<'dom, Node>(
let mut anonymous_style = None; let mut anonymous_style = None;
for item in items { for item in items {
match item { match item {
PseudoElementContentItem::Text(text) => { PseudoElementContentItem::Text(text) => handler.handle_text(&info, text.into()),
handler.handle_text(node, text.into(), pseudo_element_style.clone())
},
PseudoElementContentItem::Replaced(contents) => { PseudoElementContentItem::Replaced(contents) => {
let item_style = anonymous_style.get_or_insert_with(|| { let item_style = anonymous_style.get_or_insert_with(|| {
context context
@ -179,7 +214,7 @@ fn traverse_pseudo_element_contents<'dom, Node>(
.style_for_anonymous::<Node::ConcreteElement>( .style_for_anonymous::<Node::ConcreteElement>(
&context.shared_context().guards, &context.shared_context().guards,
&PseudoElement::ServoText, &PseudoElement::ServoText,
&pseudo_element_style, &info.style,
) )
}); });
let display_inline = DisplayGeneratingBox::OutsideInside { let display_inline = DisplayGeneratingBox::OutsideInside {
@ -191,9 +226,9 @@ fn traverse_pseudo_element_contents<'dom, Node>(
Display::from(item_style.get_box().display) == Display::from(item_style.get_box().display) ==
Display::GeneratingBox(display_inline) Display::GeneratingBox(display_inline)
); );
let info = info.new_replacing_style(item_style.clone());
handler.handle_element( handler.handle_element(
node, &info,
item_style.clone(),
display_inline, display_inline,
Contents::Replaced(contents), Contents::Replaced(contents),
// We dont keep pointers to boxes generated by contents of pseudo-elements // We dont keep pointers to boxes generated by contents of pseudo-elements
@ -239,16 +274,15 @@ impl NonReplacedContents {
pub(crate) fn traverse<'dom, Node>( pub(crate) fn traverse<'dom, Node>(
self, self,
context: &LayoutContext, context: &LayoutContext,
node: Node, info: &NodeAndStyleInfo<Node>,
inherited_style: &ServoArc<ComputedValues>,
handler: &mut impl TraversalHandler<'dom, Node>, handler: &mut impl TraversalHandler<'dom, Node>,
) where ) where
Node: NodeExt<'dom>, Node: NodeExt<'dom>,
{ {
match self { match self {
NonReplacedContents::OfElement => traverse_children_of(node, context, handler), NonReplacedContents::OfElement => traverse_children_of(info.node, context, handler),
NonReplacedContents::OfPseudoElement(items) => { NonReplacedContents::OfPseudoElement(items) => {
traverse_pseudo_element_contents(node, inherited_style, context, handler, items) traverse_pseudo_element_contents(info, context, handler, items)
}, },
} }
} }

View file

@ -4,9 +4,12 @@
use crate::cell::ArcRefCell; use crate::cell::ArcRefCell;
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::dom_traversal::{BoxSlot, Contents, NodeExt, NonReplacedContents, TraversalHandler}; use crate::dom_traversal::{
BoxSlot, Contents, NodeAndStyleInfo, NodeExt, NonReplacedContents, TraversalHandler,
};
use crate::element_data::LayoutBox; use crate::element_data::LayoutBox;
use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout}; use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout};
use crate::fragments::Tag;
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest}; use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest};
use crate::style_ext::DisplayGeneratingBox; use crate::style_ext::DisplayGeneratingBox;
@ -14,7 +17,6 @@ use crate::ContainingBlock;
use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::iter::{IntoParallelIterator, ParallelIterator};
use servo_arc::Arc; use servo_arc::Arc;
use std::borrow::Cow; use std::borrow::Cow;
use style::properties::ComputedValues;
use style::values::computed::Length; use style::values::computed::Length;
use style::values::specified::text::TextDecorationLine; use style::values::specified::text::TextDecorationLine;
use style::Zero; use style::Zero;
@ -35,24 +37,22 @@ pub(crate) enum FlexLevelBox {
impl FlexContainer { impl FlexContainer {
pub fn construct<'dom>( pub fn construct<'dom>(
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>, info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
style: &Arc<ComputedValues>,
contents: NonReplacedContents, contents: NonReplacedContents,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine, propagated_text_decoration_line: TextDecorationLine,
) -> (Self, BoxContentSizes) { ) -> (Self, BoxContentSizes) {
let text_decoration_line = let text_decoration_line =
propagated_text_decoration_line | style.clone_text_decoration_line(); propagated_text_decoration_line | info.style.clone_text_decoration_line();
let mut builder = FlexContainerBuilder { let mut builder = FlexContainerBuilder {
context, context,
node, info,
style,
text_decoration_line, text_decoration_line,
contiguous_text_runs: Vec::new(), contiguous_text_runs: Vec::new(),
jobs: Vec::new(), jobs: Vec::new(),
has_text_runs: false, has_text_runs: false,
}; };
contents.traverse(context, node, style, &mut builder); contents.traverse(context, info, &mut builder);
let content_sizes = content_sizes.compute(|| { let content_sizes = content_sizes.compute(|| {
// FIXME // FIXME
ContentSizes::zero() ContentSizes::zero()
@ -64,8 +64,7 @@ impl FlexContainer {
/// https://drafts.csswg.org/css-flexbox/#flex-items /// https://drafts.csswg.org/css-flexbox/#flex-items
struct FlexContainerBuilder<'a, 'dom, Node> { struct FlexContainerBuilder<'a, 'dom, Node> {
context: &'a LayoutContext<'a>, context: &'a LayoutContext<'a>,
node: Node, info: &'a NodeAndStyleInfo<Node>,
style: &'a Arc<ComputedValues>,
text_decoration_line: TextDecorationLine, text_decoration_line: TextDecorationLine,
contiguous_text_runs: Vec<TextRun<'dom, Node>>, contiguous_text_runs: Vec<TextRun<'dom, Node>>,
/// To be run in parallel with rayon in `finish` /// To be run in parallel with rayon in `finish`
@ -76,8 +75,7 @@ struct FlexContainerBuilder<'a, 'dom, Node> {
enum FlexLevelJob<'dom, Node> { enum FlexLevelJob<'dom, Node> {
/// Or pseudo-element /// Or pseudo-element
Element { Element {
node: Node, info: NodeAndStyleInfo<Node>,
style: Arc<ComputedValues>,
display: DisplayGeneratingBox, display: DisplayGeneratingBox,
contents: Contents, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
@ -86,28 +84,25 @@ enum FlexLevelJob<'dom, Node> {
} }
struct TextRun<'dom, Node> { struct TextRun<'dom, Node> {
node: Node, info: NodeAndStyleInfo<Node>,
text: Cow<'dom, str>, text: Cow<'dom, str>,
parent_style: Arc<ComputedValues>,
} }
impl<'a, 'dom, Node: 'dom> TraversalHandler<'dom, Node> for FlexContainerBuilder<'a, 'dom, Node> impl<'a, 'dom, Node: 'dom> TraversalHandler<'dom, Node> for FlexContainerBuilder<'a, 'dom, Node>
where where
Node: NodeExt<'dom>, Node: NodeExt<'dom>,
{ {
fn handle_text(&mut self, node: Node, text: Cow<'dom, str>, parent_style: Arc<ComputedValues>) { fn handle_text(&mut self, info: &NodeAndStyleInfo<Node>, text: Cow<'dom, str>) {
self.contiguous_text_runs.push(TextRun { self.contiguous_text_runs.push(TextRun {
node, info: info.clone(),
text, text,
parent_style,
}) })
} }
/// Or pseudo-element /// Or pseudo-element
fn handle_element( fn handle_element(
&mut self, &mut self,
node: Node, info: &NodeAndStyleInfo<Node>,
style: Arc<ComputedValues>,
display: DisplayGeneratingBox, display: DisplayGeneratingBox,
contents: Contents, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
@ -118,8 +113,7 @@ where
self.wrap_any_text_in_anonymous_block_container(); self.wrap_any_text_in_anonymous_block_container();
self.jobs.push(FlexLevelJob::Element { self.jobs.push(FlexLevelJob::Element {
node, info: info.clone(),
style,
display, display,
contents, contents,
box_slot, box_slot,
@ -162,7 +156,7 @@ where
.style_for_anonymous::<Node::ConcreteElement>( .style_for_anonymous::<Node::ConcreteElement>(
&self.context.shared_context().guards, &self.context.shared_context().guards,
&style::selector_parser::PseudoElement::ServoText, &style::selector_parser::PseudoElement::ServoText,
self.style, &self.info.style,
), ),
) )
} else { } else {
@ -175,20 +169,20 @@ where
FlexLevelJob::TextRuns(runs) => ArcRefCell::new(FlexLevelBox::FlexItem( FlexLevelJob::TextRuns(runs) => ArcRefCell::new(FlexLevelBox::FlexItem(
IndependentFormattingContext::construct_for_text_runs( IndependentFormattingContext::construct_for_text_runs(
self.context, self.context,
self.node, &self
anonymous_style.clone().unwrap(), .info
.new_replacing_style(anonymous_style.clone().unwrap()),
runs.into_iter().map(|run| crate::flow::inline::TextRun { runs.into_iter().map(|run| crate::flow::inline::TextRun {
tag: run.node.as_opaque(), tag: Tag::from_node_and_style_info(&run.info),
text: run.text.into(), text: run.text.into(),
parent_style: run.parent_style, parent_style: run.info.style,
}), }),
ContentSizesRequest::None, // FIXME: request sizes when we start using them ContentSizesRequest::None, // FIXME: request sizes when we start using them
self.text_decoration_line, self.text_decoration_line,
), ),
)), )),
FlexLevelJob::Element { FlexLevelJob::Element {
node, info,
style,
display, display,
contents, contents,
box_slot, box_slot,
@ -196,13 +190,12 @@ where
let display_inside = match display { let display_inside = match display {
DisplayGeneratingBox::OutsideInside { inside, .. } => inside, DisplayGeneratingBox::OutsideInside { inside, .. } => inside,
}; };
let box_ = if style.get_box().position.is_absolutely_positioned() { let box_ = if info.style.get_box().position.is_absolutely_positioned() {
// https://drafts.csswg.org/css-flexbox/#abspos-items // https://drafts.csswg.org/css-flexbox/#abspos-items
ArcRefCell::new(FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new( ArcRefCell::new(FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
AbsolutelyPositionedBox::construct( AbsolutelyPositionedBox::construct(
self.context, self.context,
node, &info,
style.clone(),
display_inside, display_inside,
contents, contents,
), ),
@ -211,8 +204,7 @@ where
ArcRefCell::new(FlexLevelBox::FlexItem( ArcRefCell::new(FlexLevelBox::FlexItem(
IndependentFormattingContext::construct( IndependentFormattingContext::construct(
self.context, self.context,
node, &info,
style.clone(),
display_inside, display_inside,
contents, contents,
ContentSizesRequest::None, // FIXME: request sizes when we start using them ContentSizesRequest::None, // FIXME: request sizes when we start using them

View file

@ -4,12 +4,15 @@
use crate::cell::ArcRefCell; use crate::cell::ArcRefCell;
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::dom_traversal::{BoxSlot, Contents, NodeExt, NonReplacedContents, TraversalHandler}; use crate::dom_traversal::{
BoxSlot, Contents, NodeAndStyleInfo, NodeExt, NonReplacedContents, TraversalHandler,
};
use crate::element_data::LayoutBox; use crate::element_data::LayoutBox;
use crate::flow::float::FloatBox; use crate::flow::float::FloatBox;
use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, TextRun}; use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, TextRun};
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Tag;
use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::AbsolutelyPositionedBox;
use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest}; use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest};
use crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox, DisplayInside, DisplayOutside}; use crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox, DisplayInside, DisplayOutside};
@ -23,18 +26,19 @@ use style::selector_parser::PseudoElement;
use style::values::specified::text::TextDecorationLine; use style::values::specified::text::TextDecorationLine;
impl BlockFormattingContext { impl BlockFormattingContext {
pub fn construct<'dom>( pub fn construct<'dom, Node>(
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>, info: &NodeAndStyleInfo<Node>,
style: &Arc<ComputedValues>,
contents: NonReplacedContents, contents: NonReplacedContents,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine, propagated_text_decoration_line: TextDecorationLine,
) -> (Self, BoxContentSizes) { ) -> (Self, BoxContentSizes)
where
Node: NodeExt<'dom>,
{
let (contents, contains_floats, inline_content_sizes) = BlockContainer::construct( let (contents, contains_floats, inline_content_sizes) = BlockContainer::construct(
context, context,
node, info,
style,
contents, contents,
content_sizes, content_sizes,
propagated_text_decoration_line, propagated_text_decoration_line,
@ -74,9 +78,8 @@ impl BlockFormattingContext {
} }
struct BlockLevelJob<'dom, Node> { struct BlockLevelJob<'dom, Node> {
node: Node, info: NodeAndStyleInfo<Node>,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
style: Arc<ComputedValues>,
kind: BlockLevelCreator, kind: BlockLevelCreator,
} }
@ -116,9 +119,9 @@ enum IntermediateBlockContainer {
struct BlockContainerBuilder<'dom, 'style, Node> { struct BlockContainerBuilder<'dom, 'style, Node> {
context: &'style LayoutContext<'style>, context: &'style LayoutContext<'style>,
root: Node, /// This NodeAndStyleInfo contains the root node, the corresponding pseudo
/// content designator, and the block container style.
block_container_style: &'style Arc<ComputedValues>, info: &'style NodeAndStyleInfo<Node>,
/// The list of block-level boxes to be built for the final block container. /// The list of block-level boxes to be built for the final block container.
/// ///
@ -168,20 +171,21 @@ struct BlockContainerBuilder<'dom, 'style, Node> {
} }
impl BlockContainer { impl BlockContainer {
pub fn construct<'dom>( pub fn construct<'dom, Node>(
context: &LayoutContext, context: &LayoutContext,
root: impl NodeExt<'dom>, info: &NodeAndStyleInfo<Node>,
block_container_style: &Arc<ComputedValues>,
contents: NonReplacedContents, contents: NonReplacedContents,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine, propagated_text_decoration_line: TextDecorationLine,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) { ) -> (BlockContainer, ContainsFloats, BoxContentSizes)
where
Node: NodeExt<'dom>,
{
let text_decoration_line = let text_decoration_line =
propagated_text_decoration_line | block_container_style.clone_text_decoration_line(); propagated_text_decoration_line | info.style.clone_text_decoration_line();
let mut builder = BlockContainerBuilder { let mut builder = BlockContainerBuilder {
context, context,
root, info,
block_container_style,
block_level_boxes: Vec::new(), block_level_boxes: Vec::new(),
ongoing_inline_formatting_context: InlineFormattingContext::new(text_decoration_line), ongoing_inline_formatting_context: InlineFormattingContext::new(text_decoration_line),
ongoing_inline_boxes_stack: Vec::new(), ongoing_inline_boxes_stack: Vec::new(),
@ -189,7 +193,7 @@ impl BlockContainer {
contains_floats: ContainsFloats::No, contains_floats: ContainsFloats::No,
}; };
contents.traverse(context, root, block_container_style, &mut builder); contents.traverse(context, info, &mut builder);
debug_assert!(builder.ongoing_inline_boxes_stack.is_empty()); debug_assert!(builder.ongoing_inline_boxes_stack.is_empty());
@ -272,8 +276,7 @@ where
{ {
fn handle_element( fn handle_element(
&mut self, &mut self,
node: Node, info: &NodeAndStyleInfo<Node>,
style: Arc<ComputedValues>,
display: DisplayGeneratingBox, display: DisplayGeneratingBox,
contents: Contents, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
@ -281,32 +284,25 @@ where
match display { match display {
DisplayGeneratingBox::OutsideInside { outside, inside } => match outside { DisplayGeneratingBox::OutsideInside { outside, inside } => match outside {
DisplayOutside::Inline => box_slot.set(LayoutBox::InlineLevel( DisplayOutside::Inline => box_slot.set(LayoutBox::InlineLevel(
self.handle_inline_level_element(node, style, inside, contents), self.handle_inline_level_element(info, inside, contents),
)), )),
DisplayOutside::Block => { DisplayOutside::Block => {
let box_style = style.get_box(); let box_style = info.style.get_box();
// Floats and abspos cause blockification, so they only happen in this case. // Floats and abspos cause blockification, so they only happen in this case.
// https://drafts.csswg.org/css2/visuren.html#dis-pos-flo // https://drafts.csswg.org/css2/visuren.html#dis-pos-flo
if box_style.position.is_absolutely_positioned() { if box_style.position.is_absolutely_positioned() {
self.handle_absolutely_positioned_element( self.handle_absolutely_positioned_element(info, inside, contents, box_slot)
node, style, inside, contents, box_slot,
)
} else if box_style.float.is_floating() { } else if box_style.float.is_floating() {
self.handle_float_element(node, style, inside, contents, box_slot) self.handle_float_element(info, inside, contents, box_slot)
} else { } else {
self.handle_block_level_element(node, style, inside, contents, box_slot) self.handle_block_level_element(info, inside, contents, box_slot)
} }
}, },
}, },
} }
} }
fn handle_text( fn handle_text(&mut self, info: &NodeAndStyleInfo<Node>, input: Cow<'dom, str>) {
&mut self,
node: Node,
input: Cow<'dom, str>,
parent_style: Arc<ComputedValues>,
) {
let (leading_whitespace, mut input) = self.handle_leading_whitespace(&input); let (leading_whitespace, mut input) = self.handle_leading_whitespace(&input);
if leading_whitespace || !input.is_empty() { if leading_whitespace || !input.is_empty() {
// This text node should be pushed either to the next ongoing // This text node should be pushed either to the next ongoing
@ -356,8 +352,8 @@ where
if let Some(text) = new_text_run_contents { if let Some(text) = new_text_run_contents {
inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun { inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun {
tag: node.as_opaque(), tag: Tag::from_node_and_style_info(info),
parent_style, parent_style: Arc::clone(&info.style),
text, text,
}))) })))
} }
@ -430,30 +426,27 @@ where
fn handle_inline_level_element( fn handle_inline_level_element(
&mut self, &mut self,
node: Node, info: &NodeAndStyleInfo<Node>,
style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
) -> ArcRefCell<InlineLevelBox> { ) -> ArcRefCell<InlineLevelBox> {
let style = &info.style;
let box_ = if display_inside == DisplayInside::Flow && !contents.is_replaced() { let box_ = if display_inside == DisplayInside::Flow && !contents.is_replaced() {
// We found un inline box. // We found un inline box.
// Whatever happened before, all we need to do before recurring // Whatever happened before, all we need to do before recurring
// is to remember this ongoing inline level box. // is to remember this ongoing inline level box.
self.ongoing_inline_boxes_stack.push(InlineBox { self.ongoing_inline_boxes_stack.push(InlineBox {
tag: node.as_opaque(), tag: Tag::from_node_and_style_info(info),
style: style.clone(), style: info.style.clone(),
first_fragment: true, first_fragment: true,
last_fragment: false, last_fragment: false,
children: vec![], children: vec![],
}); });
// `unwrap` doesnt panic here because `is_replaced` returned `false`. // `unwrap` doesnt panic here because `is_replaced` returned `false`.
NonReplacedContents::try_from(contents).unwrap().traverse( NonReplacedContents::try_from(contents)
self.context, .unwrap()
node, .traverse(self.context, info, self);
&style,
self,
);
let mut inline_box = self let mut inline_box = self
.ongoing_inline_boxes_stack .ongoing_inline_boxes_stack
@ -466,8 +459,7 @@ where
ArcRefCell::new(InlineLevelBox::Atomic( ArcRefCell::new(InlineLevelBox::Atomic(
IndependentFormattingContext::construct( IndependentFormattingContext::construct(
self.context, self.context,
node, info,
style,
display_inside, display_inside,
contents, contents,
content_sizes, content_sizes,
@ -482,8 +474,7 @@ where
fn handle_block_level_element( fn handle_block_level_element(
&mut self, &mut self,
node: Node, info: &NodeAndStyleInfo<Node>,
style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
@ -556,17 +547,15 @@ where
}, },
}; };
self.block_level_boxes.push(BlockLevelJob { self.block_level_boxes.push(BlockLevelJob {
node, info: info.clone(),
box_slot, box_slot,
style,
kind, kind,
}); });
} }
fn handle_absolutely_positioned_element( fn handle_absolutely_positioned_element(
&mut self, &mut self,
node: Node, info: &NodeAndStyleInfo<Node>,
style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
@ -577,20 +566,13 @@ where
display_inside, display_inside,
}; };
self.block_level_boxes.push(BlockLevelJob { self.block_level_boxes.push(BlockLevelJob {
node, info: info.clone(),
box_slot, box_slot,
style,
kind, kind,
}); });
} else { } else {
let box_ = ArcRefCell::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new( let box_ = ArcRefCell::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
AbsolutelyPositionedBox::construct( AbsolutelyPositionedBox::construct(self.context, info, display_inside, contents),
self.context,
node,
style,
display_inside,
contents,
),
))); )));
self.current_inline_level_boxes().push(box_.clone()); self.current_inline_level_boxes().push(box_.clone());
box_slot.set(LayoutBox::InlineLevel(box_)) box_slot.set(LayoutBox::InlineLevel(box_))
@ -599,8 +581,7 @@ where
fn handle_float_element( fn handle_float_element(
&mut self, &mut self,
node: Node, info: &NodeAndStyleInfo<Node>,
style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
@ -613,16 +594,14 @@ where
display_inside, display_inside,
}; };
self.block_level_boxes.push(BlockLevelJob { self.block_level_boxes.push(BlockLevelJob {
node, info: info.clone(),
box_slot, box_slot,
style,
kind, kind,
}); });
} else { } else {
let box_ = ArcRefCell::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct( let box_ = ArcRefCell::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct(
self.context, self.context,
node, info,
style,
display_inside, display_inside,
contents, contents,
))); )));
@ -642,7 +621,7 @@ where
} }
let context = self.context; let context = self.context;
let block_container_style = self.block_container_style; let block_container_style = &self.info.style;
let anonymous_style = self.anonymous_style.get_or_insert_with(|| { let anonymous_style = self.anonymous_style.get_or_insert_with(|| {
context context
.shared_context() .shared_context()
@ -650,7 +629,7 @@ where
.style_for_anonymous::<Node::ConcreteElement>( .style_for_anonymous::<Node::ConcreteElement>(
&context.shared_context().guards, &context.shared_context().guards,
&PseudoElement::ServoText, &PseudoElement::ServoText,
&block_container_style, block_container_style,
) )
}); });
@ -659,11 +638,11 @@ where
&mut self.ongoing_inline_formatting_context, &mut self.ongoing_inline_formatting_context,
)), )),
); );
let info = self.info.new_replacing_style(anonymous_style.clone());
self.block_level_boxes.push(BlockLevelJob { self.block_level_boxes.push(BlockLevelJob {
node: self.root, info,
// FIXME(nox): We should be storing this somewhere. // FIXME(nox): We should be storing this somewhere.
box_slot: BoxSlot::dummy(), box_slot: BoxSlot::dummy(),
style: anonymous_style.clone(),
kind, kind,
}); });
} }
@ -693,26 +672,24 @@ where
context: &LayoutContext, context: &LayoutContext,
max_assign_in_flow_outer_content_sizes_to: Option<&mut ContentSizes>, max_assign_in_flow_outer_content_sizes_to: Option<&mut ContentSizes>,
) -> (ArcRefCell<BlockLevelBox>, ContainsFloats) { ) -> (ArcRefCell<BlockLevelBox>, ContainsFloats) {
let node = self.node; let info = &self.info;
let style = self.style;
let (block_level_box, contains_floats) = match self.kind { let (block_level_box, contains_floats) = match self.kind {
BlockLevelCreator::SameFormattingContextBlock(contents) => { BlockLevelCreator::SameFormattingContextBlock(contents) => {
let (contents, contains_floats, box_content_sizes) = contents.finish( let (contents, contains_floats, box_content_sizes) = contents.finish(
context, context,
node, info,
&style,
ContentSizesRequest::inline_if( ContentSizesRequest::inline_if(
max_assign_in_flow_outer_content_sizes_to.is_some() && max_assign_in_flow_outer_content_sizes_to.is_some() &&
!style.inline_size_is_length(), !info.style.inline_size_is_length(),
), ),
); );
if let Some(to) = max_assign_in_flow_outer_content_sizes_to { if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
to.max_assign(&box_content_sizes.outer_inline(&style)) to.max_assign(&box_content_sizes.outer_inline(&info.style))
} }
let block_level_box = ArcRefCell::new(BlockLevelBox::SameFormattingContextBlock { let block_level_box = ArcRefCell::new(BlockLevelBox::SameFormattingContextBlock {
tag: node.as_opaque(), tag: Tag::from_node_and_style_info(info),
contents, contents,
style, style: Arc::clone(&info.style),
}); });
(block_level_box, contains_floats) (block_level_box, contains_floats)
}, },
@ -723,12 +700,11 @@ where
} => { } => {
let content_sizes = ContentSizesRequest::inline_if( let content_sizes = ContentSizesRequest::inline_if(
max_assign_in_flow_outer_content_sizes_to.is_some() && max_assign_in_flow_outer_content_sizes_to.is_some() &&
!style.inline_size_is_length(), !info.style.inline_size_is_length(),
); );
let contents = IndependentFormattingContext::construct( let contents = IndependentFormattingContext::construct(
context, context,
node, info,
style,
display_inside, display_inside,
contents, contents,
content_sizes, content_sizes,
@ -748,13 +724,7 @@ where
} => { } => {
let block_level_box = let block_level_box =
ArcRefCell::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new( ArcRefCell::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
AbsolutelyPositionedBox::construct( AbsolutelyPositionedBox::construct(context, info, display_inside, contents),
context,
node,
style,
display_inside,
contents,
),
))); )));
(block_level_box, ContainsFloats::No) (block_level_box, ContainsFloats::No)
}, },
@ -763,7 +733,7 @@ where
contents, contents,
} => { } => {
let block_level_box = ArcRefCell::new(BlockLevelBox::OutOfFlowFloatBox( let block_level_box = ArcRefCell::new(BlockLevelBox::OutOfFlowFloatBox(
FloatBox::construct(context, node, style, display_inside, contents), FloatBox::construct(context, info, display_inside, contents),
)); ));
(block_level_box, ContainsFloats::Yes) (block_level_box, ContainsFloats::Yes)
}, },
@ -775,19 +745,20 @@ where
} }
impl IntermediateBlockContainer { impl IntermediateBlockContainer {
fn finish<'dom>( fn finish<'dom, Node>(
self, self,
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>, info: &NodeAndStyleInfo<Node>,
style: &Arc<ComputedValues>,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) { ) -> (BlockContainer, ContainsFloats, BoxContentSizes)
where
Node: NodeExt<'dom>,
{
match self { match self {
IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line) => { IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line) => {
BlockContainer::construct( BlockContainer::construct(
context, context,
node, info,
style,
contents, contents,
content_sizes, content_sizes,
propagated_text_decoration_line, propagated_text_decoration_line,

View file

@ -3,12 +3,10 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt}; use crate::dom_traversal::{Contents, NodeAndStyleInfo, NodeExt};
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::sizing::ContentSizesRequest; use crate::sizing::ContentSizesRequest;
use crate::style_ext::{ComputedValuesExt, DisplayInside}; use crate::style_ext::{ComputedValuesExt, DisplayInside};
use servo_arc::Arc;
use style::properties::ComputedValues;
use style::values::specified::text::TextDecorationLine; use style::values::specified::text::TextDecorationLine;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
@ -30,17 +28,15 @@ impl FloatContext {
impl FloatBox { impl FloatBox {
pub fn construct<'dom>( pub fn construct<'dom>(
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>, info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
) -> Self { ) -> Self {
let content_sizes = ContentSizesRequest::inline_if(!style.inline_size_is_length()); let content_sizes = ContentSizesRequest::inline_if(!info.style.inline_size_is_length());
Self { Self {
contents: IndependentFormattingContext::construct( contents: IndependentFormattingContext::construct(
context, context,
node, info,
style,
display_inside, display_inside,
contents, contents,
content_sizes, content_sizes,

View file

@ -9,7 +9,7 @@ use crate::flow::FlowLayout;
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{ use crate::fragments::{
AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins, AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins,
DebugId, FontMetrics, Fragment, TextFragment, DebugId, FontMetrics, Fragment, Tag, TextFragment,
}; };
use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{ use crate::positioned::{
@ -22,7 +22,6 @@ use crate::ContainingBlock;
use app_units::Au; use app_units::Au;
use gfx::text::text_run::GlyphRun; use gfx::text::text_run::GlyphRun;
use servo_arc::Arc; use servo_arc::Arc;
use style::dom::OpaqueNode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthPercentage, Percentage}; use style::values::computed::{Length, LengthPercentage, Percentage};
use style::values::specified::text::TextAlignKeyword; use style::values::specified::text::TextAlignKeyword;
@ -47,7 +46,7 @@ pub(crate) enum InlineLevelBox {
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub(crate) struct InlineBox { pub(crate) struct InlineBox {
pub tag: OpaqueNode, pub tag: Tag,
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub style: Arc<ComputedValues>, pub style: Arc<ComputedValues>,
pub first_fragment: bool, pub first_fragment: bool,
@ -58,7 +57,7 @@ pub(crate) struct InlineBox {
/// https://www.w3.org/TR/css-display-3/#css-text-run /// https://www.w3.org/TR/css-display-3/#css-text-run
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub(crate) struct TextRun { pub(crate) struct TextRun {
pub tag: OpaqueNode, pub tag: Tag,
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub parent_style: Arc<ComputedValues>, pub parent_style: Arc<ComputedValues>,
pub text: String, pub text: String,
@ -78,7 +77,7 @@ struct InlineNestingLevelState<'box_tree> {
} }
struct PartialInlineBoxFragment<'box_tree> { struct PartialInlineBoxFragment<'box_tree> {
tag: OpaqueNode, tag: Tag,
style: Arc<ComputedValues>, style: Arc<ComputedValues>,
start_corner: Vec2<Length>, start_corner: Vec2<Length>,
padding: Sides<Length>, padding: Sides<Length>,

View file

@ -9,8 +9,10 @@ use crate::context::LayoutContext;
use crate::flow::float::{FloatBox, FloatContext}; use crate::flow::float::{FloatBox, FloatContext};
use crate::flow::inline::InlineFormattingContext; use crate::flow::inline::InlineFormattingContext;
use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout, NonReplacedIFC}; use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout, NonReplacedIFC};
use crate::fragments::{AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment}; use crate::fragments::{
use crate::fragments::{CollapsedBlockMargins, CollapsedMargin, Fragment}; AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins,
CollapsedMargin, Fragment, Tag,
};
use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;
@ -19,7 +21,6 @@ use crate::ContainingBlock;
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use rayon_croissant::ParallelIteratorExt; use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc; use servo_arc::Arc;
use style::dom::OpaqueNode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto}; use style::values::computed::{Length, LengthOrAuto};
use style::Zero; use style::Zero;
@ -46,7 +47,7 @@ pub(crate) enum BlockContainer {
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub(crate) enum BlockLevelBox { pub(crate) enum BlockLevelBox {
SameFormattingContextBlock { SameFormattingContextBlock {
tag: OpaqueNode, tag: Tag,
#[serde(skip_serializing)] #[serde(skip_serializing)]
style: Arc<ComputedValues>, style: Arc<ComputedValues>,
contents: BlockContainer, contents: BlockContainer,
@ -345,7 +346,7 @@ fn layout_in_flow_non_replaced_block_level(
layout_context: &LayoutContext, layout_context: &LayoutContext,
positioning_context: &mut PositioningContext, positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
tag: OpaqueNode, tag: Tag,
style: &Arc<ComputedValues>, style: &Arc<ComputedValues>,
block_level_kind: NonReplacedContents, block_level_kind: NonReplacedContents,
tree_rank: usize, tree_rank: usize,
@ -500,7 +501,7 @@ fn layout_in_flow_non_replaced_block_level(
/// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height /// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height
fn layout_in_flow_replaced_block_level<'a>( fn layout_in_flow_replaced_block_level<'a>(
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
tag: OpaqueNode, tag: Tag,
style: &Arc<ComputedValues>, style: &Arc<ComputedValues>,
replaced: &ReplacedContent, replaced: &ReplacedContent,
) -> BoxFragment { ) -> BoxFragment {

View file

@ -8,7 +8,7 @@ use crate::display_list::stacking_context::{
ContainingBlock, ContainingBlockInfo, StackingContext, StackingContextBuildMode, ContainingBlock, ContainingBlockInfo, StackingContext, StackingContextBuildMode,
StackingContextBuilder, StackingContextBuilder,
}; };
use crate::dom_traversal::{iter_child_nodes, Contents, NodeExt}; use crate::dom_traversal::{iter_child_nodes, Contents, NodeAndStyleInfo, NodeExt};
use crate::element_data::LayoutBox; use crate::element_data::LayoutBox;
use crate::flexbox::FlexLevelBox; use crate::flexbox::FlexLevelBox;
use crate::flow::construct::ContainsFloats; use crate::flow::construct::ContainsFloats;
@ -16,7 +16,7 @@ use crate::flow::float::FloatBox;
use crate::flow::inline::InlineLevelBox; use crate::flow::inline::InlineLevelBox;
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment; use crate::fragments::{Fragment, Tag};
use crate::geom::flow_relative::Vec2; use crate::geom::flow_relative::Vec2;
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize}; use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::AbsolutelyPositionedBox;
@ -206,14 +206,10 @@ impl BoxTree {
if let Some((primary_style, display_inside, update_point)) = update_point(dirty_node) { if let Some((primary_style, display_inside, update_point)) = update_point(dirty_node) {
let contents = ReplacedContent::for_element(dirty_node) let contents = ReplacedContent::for_element(dirty_node)
.map_or(Contents::OfElement, Contents::Replaced); .map_or(Contents::OfElement, Contents::Replaced);
let out_of_flow_absolutely_positioned_box = let info = NodeAndStyleInfo::new(dirty_node, Arc::clone(&primary_style));
Arc::new(AbsolutelyPositionedBox::construct( let out_of_flow_absolutely_positioned_box = Arc::new(
context, AbsolutelyPositionedBox::construct(context, &info, display_inside, contents),
dirty_node, );
primary_style,
display_inside,
contents,
));
match update_point { match update_point {
UpdatePoint::AbsolutelyPositionedBlockLevelBox(block_level_box) => { UpdatePoint::AbsolutelyPositionedBlockLevelBox(block_level_box) => {
*block_level_box.borrow_mut() = *block_level_box.borrow_mut() =
@ -248,8 +244,8 @@ fn construct_for_root_element<'dom>(
context: &LayoutContext, context: &LayoutContext,
root_element: impl NodeExt<'dom>, root_element: impl NodeExt<'dom>,
) -> (ContainsFloats, Vec<ArcRefCell<BlockLevelBox>>) { ) -> (ContainsFloats, Vec<ArcRefCell<BlockLevelBox>>) {
let style = root_element.style(context); let info = NodeAndStyleInfo::new(root_element, root_element.style(context));
let box_style = style.get_box(); let box_style = info.style.get_box();
let display_inside = match Display::from(box_style.display) { let display_inside = match Display::from(box_style.display) {
Display::None => { Display::None => {
@ -272,13 +268,7 @@ fn construct_for_root_element<'dom>(
( (
ContainsFloats::No, ContainsFloats::No,
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new( BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
AbsolutelyPositionedBox::construct( AbsolutelyPositionedBox::construct(context, &info, display_inside, contents),
context,
root_element,
style,
display_inside,
contents,
),
)), )),
) )
} else if box_style.float.is_floating() { } else if box_style.float.is_floating() {
@ -286,20 +276,18 @@ fn construct_for_root_element<'dom>(
ContainsFloats::Yes, ContainsFloats::Yes,
BlockLevelBox::OutOfFlowFloatBox(FloatBox::construct( BlockLevelBox::OutOfFlowFloatBox(FloatBox::construct(
context, context,
root_element, &info,
style,
display_inside, display_inside,
contents, contents,
)), )),
) )
} else { } else {
let propagated_text_decoration_line = style.clone_text_decoration_line(); let propagated_text_decoration_line = info.style.clone_text_decoration_line();
( (
ContainsFloats::No, ContainsFloats::No,
BlockLevelBox::Independent(IndependentFormattingContext::construct( BlockLevelBox::Independent(IndependentFormattingContext::construct(
context, context,
root_element, &info,
style,
display_inside, display_inside,
contents, contents,
ContentSizesRequest::None, ContentSizesRequest::None,
@ -461,7 +449,7 @@ impl FragmentTree {
pub fn remove_nodes_in_fragment_tree_from_set(&self, set: &mut FxHashSet<OpaqueNode>) { pub fn remove_nodes_in_fragment_tree_from_set(&self, set: &mut FxHashSet<OpaqueNode>) {
self.find(|fragment, _| { self.find(|fragment, _| {
if let Some(tag) = fragment.tag().as_ref() { if let Some(tag) = fragment.tag().as_ref() {
set.remove(tag); set.remove(&tag.node());
} }
None::<()> None::<()>
}); });
@ -469,8 +457,9 @@ impl FragmentTree {
pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect<Au> { pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect<Au> {
let mut bounding_box = PhysicalRect::zero(); let mut bounding_box = PhysicalRect::zero();
let tag_to_find = Tag::Node(requested_node);
self.find(|fragment, containing_block| { self.find(|fragment, containing_block| {
if fragment.tag() != Some(requested_node) { if fragment.tag() != Some(tag_to_find) {
return None::<()>; return None::<()>;
} }
@ -507,7 +496,7 @@ impl FragmentTree {
pub fn get_border_dimensions_for_node(&self, requested_node: OpaqueNode) -> Rect<i32> { pub fn get_border_dimensions_for_node(&self, requested_node: OpaqueNode) -> Rect<i32> {
self.find(|fragment, containing_block| { self.find(|fragment, containing_block| {
let (style, padding_rect) = match fragment { let (style, padding_rect) = match fragment {
Fragment::Box(fragment) if fragment.tag == requested_node => { Fragment::Box(fragment) if fragment.tag.node() == requested_node => {
(&fragment.style, fragment.padding_rect()) (&fragment.style, fragment.padding_rect())
}, },
Fragment::AbsoluteOrFixedPositioned(_) | Fragment::AbsoluteOrFixedPositioned(_) |

View file

@ -3,10 +3,10 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt}; use crate::dom_traversal::{Contents, NodeAndStyleInfo, NodeExt};
use crate::flexbox::FlexContainer; use crate::flexbox::FlexContainer;
use crate::flow::BlockFormattingContext; use crate::flow::BlockFormattingContext;
use crate::fragments::Fragment; use crate::fragments::{Fragment, Tag};
use crate::positioned::PositioningContext; use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;
use crate::sizing::{BoxContentSizes, ContentSizesRequest}; use crate::sizing::{BoxContentSizes, ContentSizesRequest};
@ -14,7 +14,6 @@ use crate::style_ext::DisplayInside;
use crate::ContainingBlock; use crate::ContainingBlock;
use servo_arc::Arc; use servo_arc::Arc;
use std::convert::TryInto; use std::convert::TryInto;
use style::dom::OpaqueNode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::Length; use style::values::computed::Length;
use style::values::specified::text::TextDecorationLine; use style::values::specified::text::TextDecorationLine;
@ -22,7 +21,7 @@ use style::values::specified::text::TextDecorationLine;
/// https://drafts.csswg.org/css-display/#independent-formatting-context /// https://drafts.csswg.org/css-display/#independent-formatting-context
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub(crate) struct IndependentFormattingContext { pub(crate) struct IndependentFormattingContext {
pub tag: OpaqueNode, pub tag: Tag,
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub style: Arc<ComputedValues>, pub style: Arc<ComputedValues>,
@ -61,8 +60,7 @@ enum NonReplacedIFCKind<'a> {
impl IndependentFormattingContext { impl IndependentFormattingContext {
pub fn construct<'dom>( pub fn construct<'dom>(
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>, info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
@ -73,15 +71,14 @@ impl IndependentFormattingContext {
DisplayInside::Flow | DisplayInside::FlowRoot => { DisplayInside::Flow | DisplayInside::FlowRoot => {
let (bfc, content_sizes) = BlockFormattingContext::construct( let (bfc, content_sizes) = BlockFormattingContext::construct(
context, context,
node, info,
&style,
non_replaced, non_replaced,
content_sizes, content_sizes,
propagated_text_decoration_line, propagated_text_decoration_line,
); );
Self { Self {
tag: node.as_opaque(), tag: Tag::from_node_and_style_info(info),
style, style: Arc::clone(&info.style),
content_sizes, content_sizes,
contents: IndependentFormattingContextContents::Flow(bfc), contents: IndependentFormattingContextContents::Flow(bfc),
} }
@ -89,25 +86,25 @@ impl IndependentFormattingContext {
DisplayInside::Flex => { DisplayInside::Flex => {
let (fc, content_sizes) = FlexContainer::construct( let (fc, content_sizes) = FlexContainer::construct(
context, context,
node, info,
&style,
non_replaced, non_replaced,
content_sizes, content_sizes,
propagated_text_decoration_line, propagated_text_decoration_line,
); );
Self { Self {
tag: node.as_opaque(), tag: Tag::from_node_and_style_info(info),
style, style: Arc::clone(&info.style),
content_sizes, content_sizes,
contents: IndependentFormattingContextContents::Flex(fc), contents: IndependentFormattingContextContents::Flex(fc),
} }
}, },
}, },
Err(replaced) => { Err(replaced) => {
let content_sizes = content_sizes.compute(|| replaced.inline_content_sizes(&style)); let content_sizes =
content_sizes.compute(|| replaced.inline_content_sizes(&info.style));
Self { Self {
tag: node.as_opaque(), tag: Tag::from_node_and_style_info(info),
style, style: Arc::clone(&info.style),
content_sizes, content_sizes,
contents: IndependentFormattingContextContents::Replaced(replaced), contents: IndependentFormattingContextContents::Replaced(replaced),
} }
@ -117,8 +114,7 @@ impl IndependentFormattingContext {
pub fn construct_for_text_runs<'dom>( pub fn construct_for_text_runs<'dom>(
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>, info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
style: Arc<ComputedValues>,
runs: impl Iterator<Item = crate::flow::inline::TextRun>, runs: impl Iterator<Item = crate::flow::inline::TextRun>,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine, propagated_text_decoration_line: TextDecorationLine,
@ -130,8 +126,8 @@ impl IndependentFormattingContext {
propagated_text_decoration_line, propagated_text_decoration_line,
); );
Self { Self {
tag: node.as_opaque(), tag: Tag::from_node_and_style_info(info),
style, style: Arc::clone(&info.style),
content_sizes, content_sizes,
contents: IndependentFormattingContextContents::Flow(bfc), contents: IndependentFormattingContextContents::Flow(bfc),
} }

View file

@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::cell::ArcRefCell; use crate::cell::ArcRefCell;
use crate::dom_traversal::{NodeAndStyleInfo, NodeExt, WhichPseudoElement};
use crate::geom::flow_relative::{Rect, Sides}; use crate::geom::flow_relative::{Rect, Sides};
use crate::geom::{PhysicalPoint, PhysicalRect}; use crate::geom::{PhysicalPoint, PhysicalRect};
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -10,6 +11,7 @@ use crate::layout_debug;
use gfx::font::FontMetrics as GfxFontMetrics; use gfx::font::FontMetrics as GfxFontMetrics;
use gfx::text::glyph::GlyphStore; use gfx::text::glyph::GlyphStore;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use gfx_traits::{combine_id_with_fragment_type, FragmentType};
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
use serde::ser::{Serialize, Serializer}; use serde::ser::{Serialize, Serializer};
use servo_arc::Arc as ServoArc; use servo_arc::Arc as ServoArc;
@ -24,6 +26,42 @@ use style::values::specified::text::TextDecorationLine;
use style::Zero; use style::Zero;
use webrender_api::{FontInstanceKey, ImageKey}; use webrender_api::{FontInstanceKey, ImageKey};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
pub(crate) enum Tag {
Node(OpaqueNode),
BeforePseudo(OpaqueNode),
AfterPseudo(OpaqueNode),
}
impl Tag {
pub(crate) fn node(&self) -> OpaqueNode {
match self {
Self::Node(node) | Self::AfterPseudo(node) | Self::BeforePseudo(node) => *node,
}
}
pub(crate) fn to_display_list_fragment_id(&self) -> u64 {
let (node, content_type) = match self {
Self::Node(node) => (node, FragmentType::FragmentBody),
Self::AfterPseudo(node) => (node, FragmentType::BeforePseudoContent),
Self::BeforePseudo(node) => (node, FragmentType::AfterPseudoContent),
};
combine_id_with_fragment_type(node.id() as usize, content_type) as u64
}
pub(crate) fn from_node_and_style_info<'dom, Node>(info: &NodeAndStyleInfo<Node>) -> Self
where
Node: NodeExt<'dom>,
{
let opaque_node = info.node.as_opaque();
match info.pseudo_element_type {
None => Self::Node(opaque_node),
Some(WhichPseudoElement::Before) => Self::BeforePseudo(opaque_node),
Some(WhichPseudoElement::After) => Self::AfterPseudo(opaque_node),
}
}
}
#[derive(Serialize)] #[derive(Serialize)]
pub(crate) enum Fragment { pub(crate) enum Fragment {
Box(BoxFragment), Box(BoxFragment),
@ -41,7 +79,7 @@ pub(crate) struct AbsoluteOrFixedPositionedFragment {
#[derive(Serialize)] #[derive(Serialize)]
pub(crate) struct BoxFragment { pub(crate) struct BoxFragment {
pub tag: OpaqueNode, pub tag: Tag,
pub debug_id: DebugId, pub debug_id: DebugId,
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub style: ServoArc<ComputedValues>, pub style: ServoArc<ComputedValues>,
@ -113,7 +151,7 @@ impl From<&GfxFontMetrics> for FontMetrics {
#[derive(Serialize)] #[derive(Serialize)]
pub(crate) struct TextFragment { pub(crate) struct TextFragment {
pub debug_id: DebugId, pub debug_id: DebugId,
pub tag: OpaqueNode, pub tag: Tag,
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub parent_style: ServoArc<ComputedValues>, pub parent_style: ServoArc<ComputedValues>,
pub rect: Rect<Length>, pub rect: Rect<Length>,
@ -148,7 +186,7 @@ impl Fragment {
position.inline += *offset; position.inline += *offset;
} }
pub fn tag(&self) -> Option<OpaqueNode> { pub fn tag(&self) -> Option<Tag> {
match self { match self {
Fragment::Box(fragment) => Some(fragment.tag), Fragment::Box(fragment) => Some(fragment.tag),
Fragment::Text(fragment) => Some(fragment.tag), Fragment::Text(fragment) => Some(fragment.tag),
@ -278,7 +316,7 @@ impl AnonymousFragment {
impl BoxFragment { impl BoxFragment {
pub fn new( pub fn new(
tag: OpaqueNode, tag: Tag,
style: ServoArc<ComputedValues>, style: ServoArc<ComputedValues>,
children: Vec<Fragment>, children: Vec<Fragment>,
content_rect: Rect<Length>, content_rect: Rect<Length>,

View file

@ -4,7 +4,7 @@
use crate::cell::ArcRefCell; use crate::cell::ArcRefCell;
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt}; use crate::dom_traversal::{Contents, NodeAndStyleInfo, NodeExt};
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{BoxFragment, CollapsedBlockMargins, Fragment}; use crate::fragments::{BoxFragment, CollapsedBlockMargins, Fragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::geom::flow_relative::{Rect, Sides, Vec2};
@ -71,25 +71,23 @@ pub(crate) enum AbsoluteBoxOffsets {
impl AbsolutelyPositionedBox { impl AbsolutelyPositionedBox {
pub fn construct<'dom>( pub fn construct<'dom>(
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>, node_info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
) -> Self { ) -> Self {
// "Shrink-to-fit" in https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width // "Shrink-to-fit" in https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
let content_sizes = ContentSizesRequest::inline_if( let content_sizes = ContentSizesRequest::inline_if(
// If inline-size is non-auto, that value is used without shrink-to-fit // If inline-size is non-auto, that value is used without shrink-to-fit
!style.inline_size_is_length() && !node_info.style.inline_size_is_length() &&
// If it is, then the only case where shrink-to-fit is *not* used is // If it is, then the only case where shrink-to-fit is *not* used is
// if both offsets are non-auto, leaving inline-size as the only variable // if both offsets are non-auto, leaving inline-size as the only variable
// in the constraint equation. // in the constraint equation.
!style.inline_box_offsets_are_both_non_auto(), !node_info.style.inline_box_offsets_are_both_non_auto(),
); );
Self { Self {
contents: IndependentFormattingContext::construct( contents: IndependentFormattingContext::construct(
context, context,
node, node_info,
style,
display_inside, display_inside,
contents, contents,
content_sizes, content_sizes,

View file

@ -5,7 +5,7 @@
//! Utilities for querying the layout, as needed by the layout thread. //! Utilities for querying the layout, as needed by the layout thread.
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::flow::FragmentTree; use crate::flow::FragmentTree;
use crate::fragments::Fragment; use crate::fragments::{Fragment, Tag};
use app_units::Au; use app_units::Au;
use euclid::default::{Point2D, Rect}; use euclid::default::{Point2D, Rect};
use euclid::Size2D; use euclid::Size2D;
@ -250,10 +250,13 @@ pub fn process_resolved_style_request<'dom>(
let computed_style = let computed_style =
|| style.computed_value_to_string(PropertyDeclarationId::Longhand(longhand_id)); || style.computed_value_to_string(PropertyDeclarationId::Longhand(longhand_id));
// We do not yet support pseudo content. let opaque = node.opaque();
if pseudo.is_some() { let tag_to_find = match *pseudo {
return computed_style(); None => Tag::Node(opaque),
} Some(PseudoElement::Before) => Tag::BeforePseudo(opaque),
Some(PseudoElement::After) => Tag::AfterPseudo(opaque),
Some(_) => unreachable!("Should have returned before this point."),
};
// https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle // https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle
// Here we are trying to conform to the specification that says that getComputedStyle // Here we are trying to conform to the specification that says that getComputedStyle
@ -287,9 +290,7 @@ pub fn process_resolved_style_request<'dom>(
fragment_tree fragment_tree
.find(|fragment, containing_block| { .find(|fragment, containing_block| {
let box_fragment = match fragment { let box_fragment = match fragment {
Fragment::Box(ref box_fragment) if box_fragment.tag == node.opaque() => { Fragment::Box(ref box_fragment) if box_fragment.tag == tag_to_find => box_fragment,
box_fragment
},
_ => return None, _ => return None,
}; };

View file

@ -1,10 +1,4 @@
[getComputedStyle-pseudo.html] [getComputedStyle-pseudo.html]
[Resolution of width is correct for ::before and ::after pseudo-elements of display: contents elements]
expected: FAIL
[Resolution of width is correct for ::before and ::after pseudo-elements]
expected: FAIL
[Item-based blockification of nonexistent pseudo-elements] [Item-based blockification of nonexistent pseudo-elements]
expected: FAIL expected: FAIL