mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
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:
commit
0645d8c36d
14 changed files with 271 additions and 265 deletions
|
@ -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, don’t paint it again here.
|
// This background is already painted for the canvas, don’t 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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 don’t keep pointers to boxes generated by contents of pseudo-elements
|
// We don’t 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)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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` doesn’t panic here because `is_replaced` returned `false`.
|
// `unwrap` doesn’t 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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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(_) |
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue