Auto merge of #25280 - servo:2020-hit-test, r=SimonSapin

Handle cursor and hit testing in 2020
This commit is contained in:
bors-servo 2019-12-13 13:38:08 -05:00 committed by GitHub
commit 0103ab7698
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 305 additions and 144 deletions

1
Cargo.lock generated
View file

@ -2721,6 +2721,7 @@ dependencies = [
"app_units", "app_units",
"atomic_refcell", "atomic_refcell",
"cssparser", "cssparser",
"embedder_traits",
"euclid", "euclid",
"gfx", "gfx",
"gfx_traits", "gfx_traits",

View file

@ -16,6 +16,7 @@ doctest = false
app_units = "0.7" app_units = "0.7"
atomic_refcell = "0.1" atomic_refcell = "0.1"
cssparser = "0.27" cssparser = "0.27"
embedder_traits = {path = "../embedder_traits"}
euclid = "0.20" euclid = "0.20"
gfx = {path = "../gfx"} gfx = {path = "../gfx"}
gfx_traits = {path = "../gfx_traits"} gfx_traits = {path = "../gfx_traits"}

View file

@ -4,9 +4,11 @@
use crate::fragments::{BoxFragment, Fragment}; use crate::fragments::{BoxFragment, Fragment};
use crate::geom::physical::{Rect, Vec2}; use crate::geom::physical::{Rect, Vec2};
use embedder_traits::Cursor;
use euclid::{Point2D, SideOffsets2D}; use euclid::{Point2D, SideOffsets2D};
use gfx::text::glyph::GlyphStore; use gfx::text::glyph::GlyphStore;
use std::sync::Arc; use std::sync::Arc;
use style::properties::ComputedValues;
use style::values::computed::{BorderStyle, Length}; use style::values::computed::{BorderStyle, Length};
use webrender_api::{self as wr, units, CommonItemProperties, PrimitiveFlags}; use webrender_api::{self as wr, units, CommonItemProperties, PrimitiveFlags};
@ -58,11 +60,12 @@ impl Fragment {
.translate(&containing_block.top_left); .translate(&containing_block.top_left);
let mut baseline_origin = rect.top_left.clone(); let mut baseline_origin = rect.top_left.clone();
baseline_origin.y += t.ascent; baseline_origin.y += t.ascent;
let cursor = cursor(&t.parent_style, Cursor::Text);
let common = CommonItemProperties { let common = CommonItemProperties {
clip_rect: rect.clone().into(), clip_rect: rect.clone().into(),
clip_id: wr::ClipId::root(builder.pipeline_id), clip_id: wr::ClipId::root(builder.pipeline_id),
spatial_id: wr::SpatialId::root_scroll_node(builder.pipeline_id), spatial_id: wr::SpatialId::root_scroll_node(builder.pipeline_id),
hit_info: None, hit_info: cursor.map(|cursor| (t.tag.0 as u64, cursor as u16)),
// TODO(gw): Make use of the WR backface visibility functionality. // TODO(gw): Make use of the WR backface visibility functionality.
flags: PrimitiveFlags::default(), flags: PrimitiveFlags::default(),
}; };
@ -119,11 +122,12 @@ impl BoxFragment {
.to_physical(self.style.writing_mode, containing_block) .to_physical(self.style.writing_mode, containing_block)
.translate(&containing_block.top_left) .translate(&containing_block.top_left)
.into(); .into();
let cursor = cursor(&self.style, Cursor::Default);
let common = CommonItemProperties { let common = CommonItemProperties {
clip_rect: border_rect, clip_rect: border_rect,
clip_id: wr::ClipId::root(builder.pipeline_id), clip_id: wr::ClipId::root(builder.pipeline_id),
spatial_id: wr::SpatialId::root_scroll_node(builder.pipeline_id), spatial_id: wr::SpatialId::root_scroll_node(builder.pipeline_id),
hit_info: None, hit_info: cursor.map(|cursor| (self.tag.0 as u64, cursor as u16)),
// TODO(gw): Make use of the WR backface visibility functionality. // TODO(gw): Make use of the WR backface visibility functionality.
flags: PrimitiveFlags::default(), flags: PrimitiveFlags::default(),
}; };
@ -147,7 +151,7 @@ impl BoxFragment {
let background_color = self let background_color = self
.style .style
.resolve_color(self.style.clone_background_color()); .resolve_color(self.style.clone_background_color());
if background_color.alpha > 0 { if background_color.alpha > 0 || common.hit_info.is_some() {
builder.wr.push_rect(common, rgba(background_color)) builder.wr.push_rect(common, rgba(background_color))
} }
} }
@ -228,3 +232,51 @@ fn glyphs(glyph_runs: &[Arc<GlyphStore>], mut origin: Vec2<Length>) -> Vec<wr::G
} }
glyphs glyphs
} }
fn cursor(values: &ComputedValues, default: Cursor) -> Option<Cursor> {
use style::computed_values::pointer_events::T as PointerEvents;
use style::values::specified::ui::CursorKind;
let inherited_ui = values.get_inherited_ui();
if inherited_ui.pointer_events == PointerEvents::None {
return None;
}
Some(match inherited_ui.cursor.keyword {
CursorKind::Auto => default,
CursorKind::None => Cursor::None,
CursorKind::Default => Cursor::Default,
CursorKind::Pointer => Cursor::Pointer,
CursorKind::ContextMenu => Cursor::ContextMenu,
CursorKind::Help => Cursor::Help,
CursorKind::Progress => Cursor::Progress,
CursorKind::Wait => Cursor::Wait,
CursorKind::Cell => Cursor::Cell,
CursorKind::Crosshair => Cursor::Crosshair,
CursorKind::Text => Cursor::Text,
CursorKind::VerticalText => Cursor::VerticalText,
CursorKind::Alias => Cursor::Alias,
CursorKind::Copy => Cursor::Copy,
CursorKind::Move => Cursor::Move,
CursorKind::NoDrop => Cursor::NoDrop,
CursorKind::NotAllowed => Cursor::NotAllowed,
CursorKind::Grab => Cursor::Grab,
CursorKind::Grabbing => Cursor::Grabbing,
CursorKind::EResize => Cursor::EResize,
CursorKind::NResize => Cursor::NResize,
CursorKind::NeResize => Cursor::NeResize,
CursorKind::NwResize => Cursor::NwResize,
CursorKind::SResize => Cursor::SResize,
CursorKind::SeResize => Cursor::SeResize,
CursorKind::SwResize => Cursor::SwResize,
CursorKind::WResize => Cursor::WResize,
CursorKind::EwResize => Cursor::EwResize,
CursorKind::NsResize => Cursor::NsResize,
CursorKind::NeswResize => Cursor::NeswResize,
CursorKind::NwseResize => Cursor::NwseResize,
CursorKind::ColResize => Cursor::ColResize,
CursorKind::RowResize => Cursor::RowResize,
CursorKind::AllScroll => Cursor::AllScroll,
CursorKind::ZoomIn => Cursor::ZoomIn,
CursorKind::ZoomOut => Cursor::ZoomOut,
})
}

View file

@ -14,7 +14,7 @@ use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
use servo_arc::Arc as ServoArc; use servo_arc::Arc as ServoArc;
use std::marker::PhantomData as marker; use std::marker::PhantomData as marker;
use std::sync::Arc; use std::sync::Arc;
use style::dom::TNode; use style::dom::{OpaqueNode, TNode};
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::selector_parser::PseudoElement; use style::selector_parser::PseudoElement;
@ -24,9 +24,9 @@ pub enum WhichPseudoElement {
After, After,
} }
pub(super) enum Contents<Node> { 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(Node), OfElement,
/// Example: an `<img src=…>` element. /// Example: an `<img src=…>` element.
/// <https://drafts.csswg.org/css2/conform.html#replaced-element> /// <https://drafts.csswg.org/css2/conform.html#replaced-element>
@ -37,8 +37,8 @@ pub(super) enum Contents<Node> {
OfPseudoElement(Vec<PseudoElementContentItem>), OfPseudoElement(Vec<PseudoElementContentItem>),
} }
pub(super) enum NonReplacedContents<Node> { pub(super) enum NonReplacedContents {
OfElement(Node), OfElement,
OfPseudoElement(Vec<PseudoElementContentItem>), OfPseudoElement(Vec<PseudoElementContentItem>),
} }
@ -51,14 +51,15 @@ pub(super) trait TraversalHandler<'dom, Node>
where where
Node: 'dom, Node: 'dom,
{ {
fn handle_text(&mut self, text: String, parent_style: &ServoArc<ComputedValues>); fn handle_text(&mut self, node: Node, text: String, parent_style: &ServoArc<ComputedValues>);
/// Or pseudo-element /// Or pseudo-element
fn handle_element( fn handle_element(
&mut self, &mut self,
node: Node,
style: &ServoArc<ComputedValues>, style: &ServoArc<ComputedValues>,
display: DisplayGeneratingBox, display: DisplayGeneratingBox,
contents: Contents<Node>, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
); );
} }
@ -75,7 +76,7 @@ fn traverse_children_of<'dom, Node>(
let mut next = parent_element.first_child(); let mut next = parent_element.first_child();
while let Some(child) = next { while let Some(child) = next {
if let Some(contents) = child.as_text() { if let Some(contents) = child.as_text() {
handler.handle_text(contents, &child.style(context)); handler.handle_text(child, contents, &child.style(context));
} else if child.is_element() { } else if child.is_element() {
traverse_element(child, context, handler); traverse_element(child, context, handler);
} }
@ -108,9 +109,10 @@ fn traverse_element<'dom, Node>(
}, },
Display::GeneratingBox(display) => { Display::GeneratingBox(display) => {
handler.handle_element( handler.handle_element(
element,
&style, &style,
display, display,
replaced.map_or(Contents::OfElement(element), Contents::Replaced), replaced.map_or(Contents::OfElement, Contents::Replaced),
element.element_box_slot(), element.element_box_slot(),
); );
}, },
@ -131,19 +133,20 @@ fn traverse_pseudo_element<'dom, Node>(
Display::Contents => { Display::Contents => {
element.unset_pseudo_element_box(which); element.unset_pseudo_element_box(which);
let items = generate_pseudo_element_content(&style, element, context); let items = generate_pseudo_element_content(&style, element, context);
traverse_pseudo_element_contents(&style, context, handler, items); traverse_pseudo_element_contents(element, &style, context, handler, items);
}, },
Display::GeneratingBox(display) => { Display::GeneratingBox(display) => {
let items = generate_pseudo_element_content(&style, element, context); let items = generate_pseudo_element_content(&style, element, context);
let contents = Contents::OfPseudoElement(items); let contents = Contents::OfPseudoElement(items);
let box_slot = element.pseudo_element_box_slot(which); let box_slot = element.pseudo_element_box_slot(which);
handler.handle_element(&style, display, contents, box_slot); handler.handle_element(element, &style, display, contents, box_slot);
}, },
} }
} }
} }
fn traverse_pseudo_element_contents<'dom, Node>( fn traverse_pseudo_element_contents<'dom, Node>(
node: Node,
pseudo_element_style: &ServoArc<ComputedValues>, pseudo_element_style: &ServoArc<ComputedValues>,
context: &LayoutContext, context: &LayoutContext,
handler: &mut impl TraversalHandler<'dom, Node>, handler: &mut impl TraversalHandler<'dom, Node>,
@ -154,7 +157,9 @@ 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) => handler.handle_text(text, pseudo_element_style), PseudoElementContentItem::Text(text) => {
handler.handle_text(node, text, pseudo_element_style)
},
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
@ -176,6 +181,7 @@ fn traverse_pseudo_element_contents<'dom, Node>(
Display::GeneratingBox(display_inline) Display::GeneratingBox(display_inline)
); );
handler.handle_element( handler.handle_element(
node,
item_style, item_style,
display_inline, display_inline,
Contents::Replaced(contents), Contents::Replaced(contents),
@ -187,51 +193,51 @@ fn traverse_pseudo_element_contents<'dom, Node>(
} }
} }
impl<Node> Contents<Node> { impl Contents {
/// Returns true iff the `try_from` impl below would return `Err(_)` /// Returns true iff the `try_from` impl below would return `Err(_)`
pub fn is_replaced(&self) -> bool { pub fn is_replaced(&self) -> bool {
match self { match self {
Contents::OfElement(_) | Contents::OfPseudoElement(_) => false, Contents::OfElement | Contents::OfPseudoElement(_) => false,
Contents::Replaced(_) => true, Contents::Replaced(_) => true,
} }
} }
} }
impl<Node> std::convert::TryFrom<Contents<Node>> for NonReplacedContents<Node> { impl std::convert::TryFrom<Contents> for NonReplacedContents {
type Error = ReplacedContent; type Error = ReplacedContent;
fn try_from(contents: Contents<Node>) -> Result<Self, Self::Error> { fn try_from(contents: Contents) -> Result<Self, Self::Error> {
match contents { match contents {
Contents::OfElement(node) => Ok(NonReplacedContents::OfElement(node)), Contents::OfElement => Ok(NonReplacedContents::OfElement),
Contents::OfPseudoElement(items) => Ok(NonReplacedContents::OfPseudoElement(items)), Contents::OfPseudoElement(items) => Ok(NonReplacedContents::OfPseudoElement(items)),
Contents::Replaced(replaced) => Err(replaced), Contents::Replaced(replaced) => Err(replaced),
} }
} }
} }
impl<Node> std::convert::From<NonReplacedContents<Node>> for Contents<Node> { impl From<NonReplacedContents> for Contents {
fn from(contents: NonReplacedContents<Node>) -> Self { fn from(contents: NonReplacedContents) -> Self {
match contents { match contents {
NonReplacedContents::OfElement(node) => Contents::OfElement(node), NonReplacedContents::OfElement => Contents::OfElement,
NonReplacedContents::OfPseudoElement(items) => Contents::OfPseudoElement(items), NonReplacedContents::OfPseudoElement(items) => Contents::OfPseudoElement(items),
} }
} }
} }
impl<'dom, Node> NonReplacedContents<Node> impl NonReplacedContents {
where pub(crate) fn traverse<'dom, Node>(
Node: NodeExt<'dom>,
{
pub(crate) fn traverse(
self, self,
inherited_style: &ServoArc<ComputedValues>,
context: &LayoutContext, context: &LayoutContext,
node: Node,
inherited_style: &ServoArc<ComputedValues>,
handler: &mut impl TraversalHandler<'dom, Node>, handler: &mut impl TraversalHandler<'dom, Node>,
) { ) where
Node: NodeExt<'dom>,
{
match self { match self {
NonReplacedContents::OfElement(node) => traverse_children_of(node, context, handler), NonReplacedContents::OfElement => traverse_children_of(node, context, handler),
NonReplacedContents::OfPseudoElement(items) => { NonReplacedContents::OfPseudoElement(items) => {
traverse_pseudo_element_contents(inherited_style, context, handler, items) traverse_pseudo_element_contents(node, inherited_style, context, handler, items)
}, },
} }
} }
@ -307,6 +313,7 @@ pub(crate) trait NodeExt<'dom>: 'dom + Copy + LayoutNode + Send + Sync {
fn parent_node(self) -> Option<Self>; fn parent_node(self) -> Option<Self>;
fn style(self, context: &LayoutContext) -> ServoArc<ComputedValues>; fn style(self, context: &LayoutContext) -> ServoArc<ComputedValues>;
fn as_opaque(self) -> OpaqueNode;
fn layout_data_mut(&self) -> AtomicRefMut<LayoutDataForElement>; fn layout_data_mut(&self) -> AtomicRefMut<LayoutDataForElement>;
fn element_box_slot(&self) -> BoxSlot<'dom>; fn element_box_slot(&self) -> BoxSlot<'dom>;
fn pseudo_element_box_slot(&self, which: WhichPseudoElement) -> BoxSlot<'dom>; fn pseudo_element_box_slot(&self, which: WhichPseudoElement) -> BoxSlot<'dom>;
@ -366,6 +373,10 @@ where
self.to_threadsafe().style(context.shared_context()) self.to_threadsafe().style(context.shared_context())
} }
fn as_opaque(self) -> OpaqueNode {
self.opaque()
}
fn layout_data_mut(&self) -> AtomicRefMut<LayoutDataForElement> { fn layout_data_mut(&self) -> AtomicRefMut<LayoutDataForElement> {
self.get_raw_data() self.get_raw_data()
.map(|d| d.layout_data.borrow_mut()) .map(|d| d.layout_data.borrow_mut())

View file

@ -22,12 +22,13 @@ use style::selector_parser::PseudoElement;
impl BlockFormattingContext { impl BlockFormattingContext {
pub fn construct<'dom>( pub fn construct<'dom>(
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>,
style: &Arc<ComputedValues>, style: &Arc<ComputedValues>,
contents: NonReplacedContents<impl NodeExt<'dom>>, contents: NonReplacedContents,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
) -> (Self, BoxContentSizes) { ) -> (Self, BoxContentSizes) {
let (contents, contains_floats, inline_content_sizes) = let (contents, contains_floats, inline_content_sizes) =
BlockContainer::construct(context, style, contents, content_sizes); BlockContainer::construct(context, node, style, contents, content_sizes);
// FIXME: add contribution to `inline_content_sizes` of floats in this formatting context // FIXME: add contribution to `inline_content_sizes` of floats in this formatting context
// https://dbaron.org/css/intrinsic/#intrinsic // https://dbaron.org/css/intrinsic/#intrinsic
let bfc = Self { let bfc = Self {
@ -38,25 +39,26 @@ impl BlockFormattingContext {
} }
} }
enum IntermediateBlockLevelBox<Node> { struct BlockLevelJob<'dom, Node> {
SameFormattingContextBlock { node: Node,
style: Arc<ComputedValues>, box_slot: BoxSlot<'dom>,
contents: IntermediateBlockContainer<Node>, style: Arc<ComputedValues>,
}, kind: BlockLevelCreator,
}
enum BlockLevelCreator {
SameFormattingContextBlock(IntermediateBlockContainer),
Independent { Independent {
style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents<Node>, contents: Contents,
}, },
OutOfFlowAbsolutelyPositionedBox { OutOfFlowAbsolutelyPositionedBox {
style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents<Node>, contents: Contents,
}, },
OutOfFlowFloatBox { OutOfFlowFloatBox {
style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents<Node>, contents: Contents,
}, },
} }
@ -67,9 +69,9 @@ enum IntermediateBlockLevelBox<Node> {
/// of a given element. /// of a given element.
/// ///
/// Deferring allows using rayons `into_par_iter`. /// Deferring allows using rayons `into_par_iter`.
enum IntermediateBlockContainer<Node> { enum IntermediateBlockContainer {
InlineFormattingContext(InlineFormattingContext), InlineFormattingContext(InlineFormattingContext),
Deferred { contents: NonReplacedContents<Node> }, Deferred(NonReplacedContents),
} }
/// A builder for a block container. /// A builder for a block container.
@ -79,11 +81,13 @@ enum IntermediateBlockContainer<Node> {
struct BlockContainerBuilder<'dom, 'style, Node> { struct BlockContainerBuilder<'dom, 'style, Node> {
context: &'style LayoutContext<'style>, context: &'style LayoutContext<'style>,
root: Node,
block_container_style: &'style Arc<ComputedValues>, block_container_style: &'style Arc<ComputedValues>,
/// The list of block-level boxes of the final block container. /// The list of block-level boxes to be built for the final block container.
/// ///
/// Contains all the complete block level boxes we found traversing the tree /// Contains all the block-level jobs we found traversing the tree
/// so far, if this is empty at the end of the traversal and the ongoing /// so far, if this is empty at the end of the traversal and the ongoing
/// inline formatting context is not empty, the block container establishes /// inline formatting context is not empty, the block container establishes
/// an inline formatting context (see end of `build`). /// an inline formatting context (see end of `build`).
@ -94,7 +98,7 @@ struct BlockContainerBuilder<'dom, 'style, Node> {
/// doesn't have a next sibling, we either reached the end of the container /// doesn't have a next sibling, we either reached the end of the container
/// root or there are ongoing inline-level boxes /// root or there are ongoing inline-level boxes
/// (see `handle_block_level_element`). /// (see `handle_block_level_element`).
block_level_boxes: Vec<(IntermediateBlockLevelBox<Node>, BoxSlot<'dom>)>, block_level_boxes: Vec<BlockLevelJob<'dom, Node>>,
/// The ongoing inline formatting context of the builder. /// The ongoing inline formatting context of the builder.
/// ///
@ -131,12 +135,14 @@ struct BlockContainerBuilder<'dom, 'style, Node> {
impl BlockContainer { impl BlockContainer {
pub fn construct<'dom>( pub fn construct<'dom>(
context: &LayoutContext, context: &LayoutContext,
root: impl NodeExt<'dom>,
block_container_style: &Arc<ComputedValues>, block_container_style: &Arc<ComputedValues>,
contents: NonReplacedContents<impl NodeExt<'dom>>, contents: NonReplacedContents,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) { ) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
let mut builder = BlockContainerBuilder { let mut builder = BlockContainerBuilder {
context, context,
root,
block_container_style, block_container_style,
block_level_boxes: Vec::new(), block_level_boxes: Vec::new(),
ongoing_inline_formatting_context: InlineFormattingContext::default(), ongoing_inline_formatting_context: InlineFormattingContext::default(),
@ -145,7 +151,7 @@ impl BlockContainer {
contains_floats: ContainsFloats::No, contains_floats: ContainsFloats::No,
}; };
contents.traverse(block_container_style, context, &mut builder); contents.traverse(context, root, block_container_style, &mut builder);
debug_assert!(builder.ongoing_inline_boxes_stack.is_empty()); debug_assert!(builder.ongoing_inline_boxes_stack.is_empty());
@ -176,17 +182,14 @@ impl BlockContainer {
contains_floats: builder.contains_floats, contains_floats: builder.contains_floats,
outer_content_sizes_of_children: ContentSizes::zero(), outer_content_sizes_of_children: ContentSizes::zero(),
}; };
let mapfold = let mapfold = |acc: &mut Accumulator, creator: BlockLevelJob<'dom, _>| {
|acc: &mut Accumulator, let (block_level_box, box_contains_floats) = creator.finish(
(intermediate, box_slot): (IntermediateBlockLevelBox<_>, BoxSlot<'_>)| { context,
let (block_level_box, box_contains_floats) = intermediate.finish( content_sizes.if_requests_inline(|| &mut acc.outer_content_sizes_of_children),
context, );
content_sizes.if_requests_inline(|| &mut acc.outer_content_sizes_of_children), acc.contains_floats |= box_contains_floats;
); block_level_box
acc.contains_floats |= box_contains_floats; };
box_slot.set(LayoutBox::BlockLevel(block_level_box.clone()));
block_level_box
};
let block_level_boxes = if context.use_rayon { let block_level_boxes = if context.use_rayon {
builder builder
.block_level_boxes .block_level_boxes
@ -231,15 +234,16 @@ where
{ {
fn handle_element( fn handle_element(
&mut self, &mut self,
node: Node,
style: &Arc<ComputedValues>, style: &Arc<ComputedValues>,
display: DisplayGeneratingBox, display: DisplayGeneratingBox,
contents: Contents<Node>, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
) { ) {
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(style, inside, contents), self.handle_inline_level_element(node, style, inside, contents),
)), )),
DisplayOutside::Block => { DisplayOutside::Block => {
let box_style = style.get_box(); let box_style = style.get_box();
@ -247,22 +251,29 @@ where
// 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(
node,
style.clone(), style.clone(),
inside, inside,
contents, contents,
box_slot, box_slot,
) )
} else if box_style.float.is_floating() { } else if box_style.float.is_floating() {
self.handle_float_element(style.clone(), inside, contents, box_slot) self.handle_float_element(node, style.clone(), inside, contents, box_slot)
} else { } else {
self.handle_block_level_element(style.clone(), inside, contents, box_slot) self.handle_block_level_element(
node,
style.clone(),
inside,
contents,
box_slot,
)
} }
}, },
}, },
} }
} }
fn handle_text(&mut self, input: String, parent_style: &Arc<ComputedValues>) { fn handle_text(&mut self, node: Node, input: String, 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
@ -319,6 +330,7 @@ where
if let Some(text) = new_text_run_contents { if let Some(text) = new_text_run_contents {
let parent_style = parent_style.clone(); let parent_style = parent_style.clone();
inlines.push(Arc::new(InlineLevelBox::TextRun(TextRun { inlines.push(Arc::new(InlineLevelBox::TextRun(TextRun {
tag: node.as_opaque(),
parent_style, parent_style,
text, text,
}))) })))
@ -368,15 +380,17 @@ where
fn handle_inline_level_element( fn handle_inline_level_element(
&mut self, &mut self,
node: Node,
style: &Arc<ComputedValues>, style: &Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents<Node>, contents: Contents,
) -> Arc<InlineLevelBox> { ) -> Arc<InlineLevelBox> {
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(),
style: style.clone(), style: style.clone(),
first_fragment: true, first_fragment: true,
last_fragment: false, last_fragment: false,
@ -384,9 +398,12 @@ where
}); });
// `unwrap` doesnt panic here because `is_replaced` returned `false`. // `unwrap` doesnt panic here because `is_replaced` returned `false`.
NonReplacedContents::try_from(contents) NonReplacedContents::try_from(contents).unwrap().traverse(
.unwrap() self.context,
.traverse(&style, self.context, self); node,
&style,
self,
);
let mut inline_box = self let mut inline_box = self
.ongoing_inline_boxes_stack .ongoing_inline_boxes_stack
@ -398,6 +415,7 @@ where
Arc::new(InlineLevelBox::Atomic( Arc::new(InlineLevelBox::Atomic(
IndependentFormattingContext::construct( IndependentFormattingContext::construct(
self.context, self.context,
node,
style.clone(), style.clone(),
display_inside, display_inside,
contents, contents,
@ -411,9 +429,10 @@ where
fn handle_block_level_element( fn handle_block_level_element(
&mut self, &mut self,
node: Node,
style: Arc<ComputedValues>, style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents<Node>, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
) { ) {
// We just found a block level element, all ongoing inline level boxes // We just found a block level element, all ongoing inline level boxes
@ -427,6 +446,7 @@ where
.rev() .rev()
.map(|ongoing| { .map(|ongoing| {
let fragmented = InlineBox { let fragmented = InlineBox {
tag: ongoing.tag,
style: ongoing.style.clone(), style: ongoing.style.clone(),
first_fragment: ongoing.first_fragment, first_fragment: ongoing.first_fragment,
// The fragmented boxes before the block level element // The fragmented boxes before the block level element
@ -459,47 +479,60 @@ where
// context needs to be ended. // context needs to be ended.
self.end_ongoing_inline_formatting_context(); self.end_ongoing_inline_formatting_context();
let intermediate_box = match contents.try_into() { let kind = match contents.try_into() {
Ok(contents) => match display_inside { Ok(contents) => match display_inside {
DisplayInside::Flow => IntermediateBlockLevelBox::SameFormattingContextBlock { DisplayInside::Flow => BlockLevelCreator::SameFormattingContextBlock(
style, IntermediateBlockContainer::Deferred(contents),
contents: IntermediateBlockContainer::Deferred { contents }, ),
}, _ => BlockLevelCreator::Independent {
_ => IntermediateBlockLevelBox::Independent {
style,
display_inside, display_inside,
contents: contents.into(), contents: contents.into(),
}, },
}, },
Err(contents) => { Err(contents) => {
let contents = Contents::Replaced(contents); let contents = Contents::Replaced(contents);
IntermediateBlockLevelBox::Independent { BlockLevelCreator::Independent {
style,
display_inside, display_inside,
contents, contents,
} }
}, },
}; };
self.block_level_boxes.push((intermediate_box, box_slot)) self.block_level_boxes.push(BlockLevelJob {
node,
box_slot,
style,
kind,
});
} }
fn handle_absolutely_positioned_element( fn handle_absolutely_positioned_element(
&mut self, &mut self,
node: Node,
style: Arc<ComputedValues>, style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents<Node>, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
) { ) {
if !self.has_ongoing_inline_formatting_context() { if !self.has_ongoing_inline_formatting_context() {
let box_ = IntermediateBlockLevelBox::OutOfFlowAbsolutelyPositionedBox { let kind = BlockLevelCreator::OutOfFlowAbsolutelyPositionedBox {
style,
contents, contents,
display_inside, display_inside,
}; };
self.block_level_boxes.push((box_, box_slot)); self.block_level_boxes.push(BlockLevelJob {
node,
box_slot,
style,
kind,
});
} else { } else {
let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox( let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(
AbsolutelyPositionedBox::construct(self.context, style, display_inside, contents), AbsolutelyPositionedBox::construct(
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_))
@ -508,23 +541,29 @@ where
fn handle_float_element( fn handle_float_element(
&mut self, &mut self,
node: Node,
style: Arc<ComputedValues>, style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents<Node>, contents: Contents,
box_slot: BoxSlot<'dom>, box_slot: BoxSlot<'dom>,
) { ) {
self.contains_floats = ContainsFloats::Yes; self.contains_floats = ContainsFloats::Yes;
if !self.has_ongoing_inline_formatting_context() { if !self.has_ongoing_inline_formatting_context() {
let box_ = IntermediateBlockLevelBox::OutOfFlowFloatBox { let kind = BlockLevelCreator::OutOfFlowFloatBox {
style,
contents, contents,
display_inside, display_inside,
}; };
self.block_level_boxes.push((box_, box_slot)); self.block_level_boxes.push(BlockLevelJob {
node,
box_slot,
style,
kind,
});
} else { } else {
let box_ = Arc::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct( let box_ = Arc::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct(
self.context, self.context,
node,
style, style,
display_inside, display_inside,
contents, contents,
@ -557,13 +596,18 @@ where
) )
}); });
let box_ = IntermediateBlockLevelBox::SameFormattingContextBlock { let kind = BlockLevelCreator::SameFormattingContextBlock(
style: anonymous_style.clone(), IntermediateBlockContainer::InlineFormattingContext(std::mem::take(
contents: IntermediateBlockContainer::InlineFormattingContext(std::mem::take(
&mut self.ongoing_inline_formatting_context, &mut self.ongoing_inline_formatting_context,
)), )),
}; );
self.block_level_boxes.push((box_, BoxSlot::dummy())) self.block_level_boxes.push(BlockLevelJob {
node: self.root,
// FIXME(nox): We should be storing this somewhere.
box_slot: BoxSlot::dummy(),
style: anonymous_style.clone(),
kind,
});
} }
fn current_inline_level_boxes(&mut self) -> &mut Vec<Arc<InlineLevelBox>> { fn current_inline_level_boxes(&mut self) -> &mut Vec<Arc<InlineLevelBox>> {
@ -582,7 +626,7 @@ where
} }
} }
impl<'dom, Node> IntermediateBlockLevelBox<Node> impl<'dom, Node> BlockLevelJob<'dom, Node>
where where
Node: NodeExt<'dom>, Node: NodeExt<'dom>,
{ {
@ -591,10 +635,13 @@ 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>,
) -> (Arc<BlockLevelBox>, ContainsFloats) { ) -> (Arc<BlockLevelBox>, ContainsFloats) {
match self { let node = self.node;
IntermediateBlockLevelBox::SameFormattingContextBlock { style, contents } => { let style = self.style;
let (block_level_box, contains_floats) = match self.kind {
BlockLevelCreator::SameFormattingContextBlock(contents) => {
let (contents, contains_floats, box_content_sizes) = contents.finish( let (contents, contains_floats, box_content_sizes) = contents.finish(
context, context,
node,
&style, &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() &&
@ -604,12 +651,14 @@ where
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(&style))
} }
let block_level_box = let block_level_box = Arc::new(BlockLevelBox::SameFormattingContextBlock {
Arc::new(BlockLevelBox::SameFormattingContextBlock { contents, style }); tag: node.as_opaque(),
contents,
style,
});
(block_level_box, contains_floats) (block_level_box, contains_floats)
}, },
IntermediateBlockLevelBox::Independent { BlockLevelCreator::Independent {
style,
display_inside, display_inside,
contents, contents,
} => { } => {
@ -619,6 +668,7 @@ where
); );
let contents = IndependentFormattingContext::construct( let contents = IndependentFormattingContext::construct(
context, context,
node,
style, style,
display_inside, display_inside,
contents, contents,
@ -632,43 +682,48 @@ where
ContainsFloats::No, ContainsFloats::No,
) )
}, },
IntermediateBlockLevelBox::OutOfFlowAbsolutelyPositionedBox { BlockLevelCreator::OutOfFlowAbsolutelyPositionedBox {
style,
display_inside, display_inside,
contents, contents,
} => { } => {
let block_level_box = Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( let block_level_box = Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
AbsolutelyPositionedBox::construct(context, style, display_inside, contents), AbsolutelyPositionedBox::construct(
context,
node,
style,
display_inside,
contents,
),
)); ));
(block_level_box, ContainsFloats::No) (block_level_box, ContainsFloats::No)
}, },
IntermediateBlockLevelBox::OutOfFlowFloatBox { BlockLevelCreator::OutOfFlowFloatBox {
style,
display_inside, display_inside,
contents, contents,
} => { } => {
let block_level_box = Arc::new(BlockLevelBox::OutOfFlowFloatBox( let block_level_box = Arc::new(BlockLevelBox::OutOfFlowFloatBox(
FloatBox::construct(context, style, display_inside, contents), FloatBox::construct(context, node, style, display_inside, contents),
)); ));
(block_level_box, ContainsFloats::Yes) (block_level_box, ContainsFloats::Yes)
}, },
} };
self.box_slot
.set(LayoutBox::BlockLevel(block_level_box.clone()));
(block_level_box, contains_floats)
} }
} }
impl<'dom, Node> IntermediateBlockContainer<Node> impl IntermediateBlockContainer {
where fn finish<'dom>(
Node: NodeExt<'dom>,
{
fn finish(
self, self,
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>,
style: &Arc<ComputedValues>, style: &Arc<ComputedValues>,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) { ) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
match self { match self {
IntermediateBlockContainer::Deferred { contents } => { IntermediateBlockContainer::Deferred(contents) => {
BlockContainer::construct(context, style, contents, content_sizes) BlockContainer::construct(context, node, style, contents, content_sizes)
}, },
IntermediateBlockContainer::InlineFormattingContext(ifc) => { IntermediateBlockContainer::InlineFormattingContext(ifc) => {
let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context)); let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context));

View file

@ -29,14 +29,16 @@ impl FloatContext {
impl FloatBox { impl FloatBox {
pub fn construct<'dom>( pub fn construct<'dom>(
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>,
style: Arc<ComputedValues>, style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents<impl NodeExt<'dom>>, contents: Contents,
) -> Self { ) -> Self {
let content_sizes = ContentSizesRequest::inline_if(!style.inline_size_is_length()); let content_sizes = ContentSizesRequest::inline_if(!style.inline_size_is_length());
Self { Self {
contents: IndependentFormattingContext::construct( contents: IndependentFormattingContext::construct(
context, context,
node,
style, style,
display_inside, display_inside,
contents, contents,

View file

@ -16,6 +16,7 @@ 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;
@ -38,6 +39,7 @@ pub(crate) enum InlineLevelBox {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct InlineBox { pub(crate) struct InlineBox {
pub tag: OpaqueNode,
pub style: Arc<ComputedValues>, pub style: Arc<ComputedValues>,
pub first_fragment: bool, pub first_fragment: bool,
pub last_fragment: bool, pub last_fragment: bool,
@ -47,6 +49,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)] #[derive(Debug)]
pub(crate) struct TextRun { pub(crate) struct TextRun {
pub tag: OpaqueNode,
pub parent_style: Arc<ComputedValues>, pub parent_style: Arc<ComputedValues>,
pub text: String, pub text: String,
} }
@ -59,6 +62,7 @@ struct InlineNestingLevelState<'box_tree> {
} }
struct PartialInlineBoxFragment<'box_tree> { struct PartialInlineBoxFragment<'box_tree> {
tag: OpaqueNode,
style: Arc<ComputedValues>, style: Arc<ComputedValues>,
start_corner: Vec2<Length>, start_corner: Vec2<Length>,
padding: Sides<Length>, padding: Sides<Length>,
@ -371,6 +375,7 @@ impl InlineBox {
start_corner += &relative_adjustement(&style, ifc.containing_block) start_corner += &relative_adjustement(&style, ifc.containing_block)
} }
PartialInlineBoxFragment { PartialInlineBoxFragment {
tag: self.tag,
style, style,
start_corner, start_corner,
padding, padding,
@ -398,6 +403,7 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
at_line_break: bool, at_line_break: bool,
) { ) {
let mut fragment = BoxFragment { let mut fragment = BoxFragment {
tag: self.tag,
style: self.style.clone(), style: self.style.clone(),
children: std::mem::take(&mut nesting_level.fragments_so_far), children: std::mem::take(&mut nesting_level.fragments_so_far),
content_rect: Rect { content_rect: Rect {
@ -465,6 +471,7 @@ fn layout_atomic<'box_tree>(
let fragments = replaced.make_fragments(&atomic.style, size.clone()); let fragments = replaced.make_fragments(&atomic.style, size.clone());
let content_rect = Rect { start_corner, size }; let content_rect = Rect { start_corner, size };
BoxFragment { BoxFragment {
tag: atomic.tag,
style: atomic.style.clone(), style: atomic.style.clone(),
children: fragments, children: fragments,
content_rect, content_rect,
@ -539,6 +546,7 @@ fn layout_atomic<'box_tree>(
}, },
}; };
BoxFragment { BoxFragment {
tag: atomic.tag,
style: atomic.style.clone(), style: atomic.style.clone(),
children: independent_layout.fragments, children: independent_layout.fragments,
content_rect, content_rect,
@ -685,6 +693,7 @@ impl TextRun {
ifc.current_nesting_level ifc.current_nesting_level
.fragments_so_far .fragments_so_far
.push(Fragment::Text(TextFragment { .push(Fragment::Text(TextFragment {
tag: self.tag,
parent_style: self.parent_style.clone(), parent_style: self.parent_style.clone(),
rect, rect,
ascent: font_ascent.into(), ascent: font_ascent.into(),

View file

@ -18,6 +18,7 @@ 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;
@ -44,6 +45,7 @@ pub(crate) enum BlockContainer {
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum BlockLevelBox { pub(crate) enum BlockLevelBox {
SameFormattingContextBlock { SameFormattingContextBlock {
tag: OpaqueNode,
style: Arc<ComputedValues>, style: Arc<ComputedValues>,
contents: BlockContainer, contents: BlockContainer,
}, },
@ -268,24 +270,27 @@ impl BlockLevelBox {
float_context: Option<&mut FloatContext>, float_context: Option<&mut FloatContext>,
) -> Fragment { ) -> Fragment {
match self { match self {
BlockLevelBox::SameFormattingContextBlock { style, contents } => { BlockLevelBox::SameFormattingContextBlock {
Fragment::Box(positioning_context.for_maybe_position_relative( tag,
layout_context, style,
containing_block, contents,
style, } => Fragment::Box(positioning_context.for_maybe_position_relative(
|positioning_context| { layout_context,
layout_in_flow_non_replaced_block_level( containing_block,
layout_context, style,
positioning_context, |positioning_context| {
containing_block, layout_in_flow_non_replaced_block_level(
style, layout_context,
NonReplacedContents::SameFormattingContextBlock(contents), positioning_context,
tree_rank, containing_block,
float_context, *tag,
) style,
}, NonReplacedContents::SameFormattingContextBlock(contents),
)) tree_rank,
}, float_context,
)
},
)),
BlockLevelBox::Independent(contents) => { BlockLevelBox::Independent(contents) => {
Fragment::Box(positioning_context.for_maybe_position_relative( Fragment::Box(positioning_context.for_maybe_position_relative(
layout_context, layout_context,
@ -294,6 +299,7 @@ impl BlockLevelBox {
|positioning_context| match contents.as_replaced() { |positioning_context| match contents.as_replaced() {
Ok(replaced) => layout_in_flow_replaced_block_level( Ok(replaced) => layout_in_flow_replaced_block_level(
containing_block, containing_block,
contents.tag,
&contents.style, &contents.style,
replaced, replaced,
), ),
@ -301,6 +307,7 @@ impl BlockLevelBox {
layout_context, layout_context,
positioning_context, positioning_context,
containing_block, containing_block,
contents.tag,
&contents.style, &contents.style,
NonReplacedContents::EstablishesAnIndependentFormattingContext( NonReplacedContents::EstablishesAnIndependentFormattingContext(
non_replaced, non_replaced,
@ -339,6 +346,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
layout_context: &LayoutContext, layout_context: &LayoutContext,
positioning_context: &mut PositioningContext<'a>, positioning_context: &mut PositioningContext<'a>,
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
tag: OpaqueNode,
style: &Arc<ComputedValues>, style: &Arc<ComputedValues>,
block_level_kind: NonReplacedContents<'a>, block_level_kind: NonReplacedContents<'a>,
tree_rank: usize, tree_rank: usize,
@ -488,6 +496,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
}, },
}; };
BoxFragment { BoxFragment {
tag,
style: style.clone(), style: style.clone(),
children: fragments, children: fragments,
content_rect, content_rect,
@ -503,6 +512,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
/// 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,
style: &Arc<ComputedValues>, style: &Arc<ComputedValues>,
replaced: &ReplacedContent, replaced: &ReplacedContent,
) -> BoxFragment { ) -> BoxFragment {
@ -536,6 +546,7 @@ fn layout_in_flow_replaced_block_level<'a>(
size, size,
}; };
BoxFragment { BoxFragment {
tag,
style: style.clone(), style: style.clone(),
children: fragments, children: fragments,
content_rect, content_rect,

View file

@ -61,19 +61,25 @@ fn construct_for_root_element<'dom>(
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside, Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
}; };
let contents = replaced.map_or(Contents::OfElement(root_element), Contents::Replaced); let contents = replaced.map_or(Contents::OfElement, Contents::Replaced);
if box_style.position.is_absolutely_positioned() { if box_style.position.is_absolutely_positioned() {
( (
ContainsFloats::No, ContainsFloats::No,
vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
AbsolutelyPositionedBox::construct(context, style, display_inside, contents), AbsolutelyPositionedBox::construct(
context,
root_element,
style,
display_inside,
contents,
),
))], ))],
) )
} else if box_style.float.is_floating() { } else if box_style.float.is_floating() {
( (
ContainsFloats::Yes, ContainsFloats::Yes,
vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox( vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(
FloatBox::construct(context, style, display_inside, contents), FloatBox::construct(context, root_element, style, display_inside, contents),
))], ))],
) )
} else { } else {
@ -82,6 +88,7 @@ fn construct_for_root_element<'dom>(
vec![Arc::new(BlockLevelBox::Independent( vec![Arc::new(BlockLevelBox::Independent(
IndependentFormattingContext::construct( IndependentFormattingContext::construct(
context, context,
root_element,
style, style,
display_inside, display_inside,
contents, contents,

View file

@ -13,12 +13,14 @@ 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;
/// https://drafts.csswg.org/css-display/#independent-formatting-context /// https://drafts.csswg.org/css-display/#independent-formatting-context
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct IndependentFormattingContext { pub(crate) struct IndependentFormattingContext {
pub tag: OpaqueNode,
pub style: Arc<ComputedValues>, pub style: Arc<ComputedValues>,
/// If it was requested during construction /// If it was requested during construction
@ -54,9 +56,10 @@ enum NonReplacedIFCKind<'a> {
impl IndependentFormattingContext { impl IndependentFormattingContext {
pub fn construct<'dom>( pub fn construct<'dom>(
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>,
style: Arc<ComputedValues>, style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents<impl NodeExt<'dom>>, contents: Contents,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
) -> Self { ) -> Self {
match contents.try_into() { match contents.try_into() {
@ -64,11 +67,13 @@ 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,
&style, &style,
non_replaced, non_replaced,
content_sizes, content_sizes,
); );
Self { Self {
tag: node.as_opaque(),
style, style,
content_sizes, content_sizes,
contents: IndependentFormattingContextContents::Flow(bfc), contents: IndependentFormattingContextContents::Flow(bfc),
@ -78,6 +83,7 @@ impl IndependentFormattingContext {
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(&style));
Self { Self {
tag: node.as_opaque(),
style, style,
content_sizes, content_sizes,
contents: IndependentFormattingContextContents::Replaced(replaced), contents: IndependentFormattingContextContents::Replaced(replaced),

View file

@ -6,6 +6,7 @@ use crate::geom::flow_relative::{Rect, Sides, Vec2};
use gfx::text::glyph::GlyphStore; use gfx::text::glyph::GlyphStore;
use servo_arc::Arc as ServoArc; use servo_arc::Arc as ServoArc;
use std::sync::Arc; use std::sync::Arc;
use style::dom::OpaqueNode;
use style::logical_geometry::WritingMode; use style::logical_geometry::WritingMode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::Length; use style::values::computed::Length;
@ -20,6 +21,7 @@ pub(crate) enum Fragment {
} }
pub(crate) struct BoxFragment { pub(crate) struct BoxFragment {
pub tag: OpaqueNode,
pub style: ServoArc<ComputedValues>, pub style: ServoArc<ComputedValues>,
pub children: Vec<Fragment>, pub children: Vec<Fragment>,
@ -55,6 +57,7 @@ pub(crate) struct AnonymousFragment {
} }
pub(crate) struct TextFragment { pub(crate) struct TextFragment {
pub tag: OpaqueNode,
pub parent_style: ServoArc<ComputedValues>, pub parent_style: ServoArc<ComputedValues>,
pub rect: Rect<Length>, pub rect: Rect<Length>,
pub ascent: Length, pub ascent: Length,

View file

@ -60,9 +60,10 @@ pub(crate) enum AbsoluteBoxOffsets {
impl AbsolutelyPositionedBox { impl AbsolutelyPositionedBox {
pub fn construct<'dom>( pub fn construct<'dom>(
context: &LayoutContext, context: &LayoutContext,
node: impl NodeExt<'dom>,
style: Arc<ComputedValues>, style: Arc<ComputedValues>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents<impl NodeExt<'dom>>, 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(
@ -76,6 +77,7 @@ impl AbsolutelyPositionedBox {
Self { Self {
contents: IndependentFormattingContext::construct( contents: IndependentFormattingContext::construct(
context, context,
node,
style, style,
display_inside, display_inside,
contents, contents,
@ -469,6 +471,7 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
}; };
BoxFragment { BoxFragment {
tag: self.absolutely_positioned_box.contents.tag,
style: style.clone(), style: style.clone(),
children: fragments, children: fragments,
content_rect, content_rect,

View file

@ -10,7 +10,7 @@ ${helpers.predefined_type(
"cursor", "cursor",
"Cursor", "Cursor",
"computed::Cursor::auto()", "computed::Cursor::auto()",
engines="gecko servo-2013", engines="gecko servo-2013 servo-2020",
initial_specified_value="specified::Cursor::auto()", initial_specified_value="specified::Cursor::auto()",
animation_value_type="discrete", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ui/#cursor", spec="https://drafts.csswg.org/css-ui/#cursor",
@ -22,7 +22,7 @@ ${helpers.predefined_type(
${helpers.single_keyword( ${helpers.single_keyword(
"pointer-events", "pointer-events",
"auto none", "auto none",
engines="gecko servo-2013", engines="gecko servo-2013 servo-2020",
animation_value_type="discrete", animation_value_type="discrete",
extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all", extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all",
spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty", spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty",