mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Auto merge of #25280 - servo:2020-hit-test, r=SimonSapin
Handle cursor and hit testing in 2020
This commit is contained in:
commit
0103ab7698
13 changed files with 305 additions and 144 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2721,6 +2721,7 @@ dependencies = [
|
|||
"app_units",
|
||||
"atomic_refcell",
|
||||
"cssparser",
|
||||
"embedder_traits",
|
||||
"euclid",
|
||||
"gfx",
|
||||
"gfx_traits",
|
||||
|
|
|
@ -16,6 +16,7 @@ doctest = false
|
|||
app_units = "0.7"
|
||||
atomic_refcell = "0.1"
|
||||
cssparser = "0.27"
|
||||
embedder_traits = {path = "../embedder_traits"}
|
||||
euclid = "0.20"
|
||||
gfx = {path = "../gfx"}
|
||||
gfx_traits = {path = "../gfx_traits"}
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
|
||||
use crate::fragments::{BoxFragment, Fragment};
|
||||
use crate::geom::physical::{Rect, Vec2};
|
||||
use embedder_traits::Cursor;
|
||||
use euclid::{Point2D, SideOffsets2D};
|
||||
use gfx::text::glyph::GlyphStore;
|
||||
use std::sync::Arc;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{BorderStyle, Length};
|
||||
use webrender_api::{self as wr, units, CommonItemProperties, PrimitiveFlags};
|
||||
|
||||
|
@ -58,11 +60,12 @@ impl Fragment {
|
|||
.translate(&containing_block.top_left);
|
||||
let mut baseline_origin = rect.top_left.clone();
|
||||
baseline_origin.y += t.ascent;
|
||||
let cursor = cursor(&t.parent_style, Cursor::Text);
|
||||
let common = CommonItemProperties {
|
||||
clip_rect: rect.clone().into(),
|
||||
clip_id: wr::ClipId::root(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.
|
||||
flags: PrimitiveFlags::default(),
|
||||
};
|
||||
|
@ -119,11 +122,12 @@ impl BoxFragment {
|
|||
.to_physical(self.style.writing_mode, containing_block)
|
||||
.translate(&containing_block.top_left)
|
||||
.into();
|
||||
let cursor = cursor(&self.style, Cursor::Default);
|
||||
let common = CommonItemProperties {
|
||||
clip_rect: border_rect,
|
||||
clip_id: wr::ClipId::root(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.
|
||||
flags: PrimitiveFlags::default(),
|
||||
};
|
||||
|
@ -147,7 +151,7 @@ impl BoxFragment {
|
|||
let background_color = self
|
||||
.style
|
||||
.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))
|
||||
}
|
||||
}
|
||||
|
@ -228,3 +232,51 @@ fn glyphs(glyph_runs: &[Arc<GlyphStore>], mut origin: Vec2<Length>) -> Vec<wr::G
|
|||
}
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
|
|||
use servo_arc::Arc as ServoArc;
|
||||
use std::marker::PhantomData as marker;
|
||||
use std::sync::Arc;
|
||||
use style::dom::TNode;
|
||||
use style::dom::{OpaqueNode, TNode};
|
||||
use style::properties::ComputedValues;
|
||||
use style::selector_parser::PseudoElement;
|
||||
|
||||
|
@ -24,9 +24,9 @@ pub enum WhichPseudoElement {
|
|||
After,
|
||||
}
|
||||
|
||||
pub(super) enum Contents<Node> {
|
||||
pub(super) enum Contents {
|
||||
/// Refers to a DOM subtree, plus `::before` and `::after` pseudo-elements.
|
||||
OfElement(Node),
|
||||
OfElement,
|
||||
|
||||
/// Example: an `<img src=…>` element.
|
||||
/// <https://drafts.csswg.org/css2/conform.html#replaced-element>
|
||||
|
@ -37,8 +37,8 @@ pub(super) enum Contents<Node> {
|
|||
OfPseudoElement(Vec<PseudoElementContentItem>),
|
||||
}
|
||||
|
||||
pub(super) enum NonReplacedContents<Node> {
|
||||
OfElement(Node),
|
||||
pub(super) enum NonReplacedContents {
|
||||
OfElement,
|
||||
OfPseudoElement(Vec<PseudoElementContentItem>),
|
||||
}
|
||||
|
||||
|
@ -51,14 +51,15 @@ pub(super) trait TraversalHandler<'dom, Node>
|
|||
where
|
||||
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
|
||||
fn handle_element(
|
||||
&mut self,
|
||||
node: Node,
|
||||
style: &ServoArc<ComputedValues>,
|
||||
display: DisplayGeneratingBox,
|
||||
contents: Contents<Node>,
|
||||
contents: Contents,
|
||||
box_slot: BoxSlot<'dom>,
|
||||
);
|
||||
}
|
||||
|
@ -75,7 +76,7 @@ fn traverse_children_of<'dom, Node>(
|
|||
let mut next = parent_element.first_child();
|
||||
while let Some(child) = next {
|
||||
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() {
|
||||
traverse_element(child, context, handler);
|
||||
}
|
||||
|
@ -108,9 +109,10 @@ fn traverse_element<'dom, Node>(
|
|||
},
|
||||
Display::GeneratingBox(display) => {
|
||||
handler.handle_element(
|
||||
element,
|
||||
&style,
|
||||
display,
|
||||
replaced.map_or(Contents::OfElement(element), Contents::Replaced),
|
||||
replaced.map_or(Contents::OfElement, Contents::Replaced),
|
||||
element.element_box_slot(),
|
||||
);
|
||||
},
|
||||
|
@ -131,19 +133,20 @@ fn traverse_pseudo_element<'dom, Node>(
|
|||
Display::Contents => {
|
||||
element.unset_pseudo_element_box(which);
|
||||
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) => {
|
||||
let items = generate_pseudo_element_content(&style, element, context);
|
||||
let contents = Contents::OfPseudoElement(items);
|
||||
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>(
|
||||
node: Node,
|
||||
pseudo_element_style: &ServoArc<ComputedValues>,
|
||||
context: &LayoutContext,
|
||||
handler: &mut impl TraversalHandler<'dom, Node>,
|
||||
|
@ -154,7 +157,9 @@ fn traverse_pseudo_element_contents<'dom, Node>(
|
|||
let mut anonymous_style = None;
|
||||
for item in items {
|
||||
match item {
|
||||
PseudoElementContentItem::Text(text) => handler.handle_text(text, pseudo_element_style),
|
||||
PseudoElementContentItem::Text(text) => {
|
||||
handler.handle_text(node, text, pseudo_element_style)
|
||||
},
|
||||
PseudoElementContentItem::Replaced(contents) => {
|
||||
let item_style = anonymous_style.get_or_insert_with(|| {
|
||||
context
|
||||
|
@ -176,6 +181,7 @@ fn traverse_pseudo_element_contents<'dom, Node>(
|
|||
Display::GeneratingBox(display_inline)
|
||||
);
|
||||
handler.handle_element(
|
||||
node,
|
||||
item_style,
|
||||
display_inline,
|
||||
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(_)`
|
||||
pub fn is_replaced(&self) -> bool {
|
||||
match self {
|
||||
Contents::OfElement(_) | Contents::OfPseudoElement(_) => false,
|
||||
Contents::OfElement | Contents::OfPseudoElement(_) => false,
|
||||
Contents::Replaced(_) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node> std::convert::TryFrom<Contents<Node>> for NonReplacedContents<Node> {
|
||||
impl std::convert::TryFrom<Contents> for NonReplacedContents {
|
||||
type Error = ReplacedContent;
|
||||
|
||||
fn try_from(contents: Contents<Node>) -> Result<Self, Self::Error> {
|
||||
fn try_from(contents: Contents) -> Result<Self, Self::Error> {
|
||||
match contents {
|
||||
Contents::OfElement(node) => Ok(NonReplacedContents::OfElement(node)),
|
||||
Contents::OfElement => Ok(NonReplacedContents::OfElement),
|
||||
Contents::OfPseudoElement(items) => Ok(NonReplacedContents::OfPseudoElement(items)),
|
||||
Contents::Replaced(replaced) => Err(replaced),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Node> std::convert::From<NonReplacedContents<Node>> for Contents<Node> {
|
||||
fn from(contents: NonReplacedContents<Node>) -> Self {
|
||||
impl From<NonReplacedContents> for Contents {
|
||||
fn from(contents: NonReplacedContents) -> Self {
|
||||
match contents {
|
||||
NonReplacedContents::OfElement(node) => Contents::OfElement(node),
|
||||
NonReplacedContents::OfElement => Contents::OfElement,
|
||||
NonReplacedContents::OfPseudoElement(items) => Contents::OfPseudoElement(items),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'dom, Node> NonReplacedContents<Node>
|
||||
where
|
||||
impl NonReplacedContents {
|
||||
pub(crate) fn traverse<'dom, Node>(
|
||||
self,
|
||||
context: &LayoutContext,
|
||||
node: Node,
|
||||
inherited_style: &ServoArc<ComputedValues>,
|
||||
handler: &mut impl TraversalHandler<'dom, Node>,
|
||||
) where
|
||||
Node: NodeExt<'dom>,
|
||||
{
|
||||
pub(crate) fn traverse(
|
||||
self,
|
||||
inherited_style: &ServoArc<ComputedValues>,
|
||||
context: &LayoutContext,
|
||||
handler: &mut impl TraversalHandler<'dom, Node>,
|
||||
) {
|
||||
match self {
|
||||
NonReplacedContents::OfElement(node) => traverse_children_of(node, context, handler),
|
||||
NonReplacedContents::OfElement => traverse_children_of(node, context, handler),
|
||||
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 style(self, context: &LayoutContext) -> ServoArc<ComputedValues>;
|
||||
|
||||
fn as_opaque(self) -> OpaqueNode;
|
||||
fn layout_data_mut(&self) -> AtomicRefMut<LayoutDataForElement>;
|
||||
fn element_box_slot(&self) -> BoxSlot<'dom>;
|
||||
fn pseudo_element_box_slot(&self, which: WhichPseudoElement) -> BoxSlot<'dom>;
|
||||
|
@ -366,6 +373,10 @@ where
|
|||
self.to_threadsafe().style(context.shared_context())
|
||||
}
|
||||
|
||||
fn as_opaque(self) -> OpaqueNode {
|
||||
self.opaque()
|
||||
}
|
||||
|
||||
fn layout_data_mut(&self) -> AtomicRefMut<LayoutDataForElement> {
|
||||
self.get_raw_data()
|
||||
.map(|d| d.layout_data.borrow_mut())
|
||||
|
|
|
@ -22,12 +22,13 @@ use style::selector_parser::PseudoElement;
|
|||
impl BlockFormattingContext {
|
||||
pub fn construct<'dom>(
|
||||
context: &LayoutContext,
|
||||
node: impl NodeExt<'dom>,
|
||||
style: &Arc<ComputedValues>,
|
||||
contents: NonReplacedContents<impl NodeExt<'dom>>,
|
||||
contents: NonReplacedContents,
|
||||
content_sizes: ContentSizesRequest,
|
||||
) -> (Self, BoxContentSizes) {
|
||||
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
|
||||
// https://dbaron.org/css/intrinsic/#intrinsic
|
||||
let bfc = Self {
|
||||
|
@ -38,25 +39,26 @@ impl BlockFormattingContext {
|
|||
}
|
||||
}
|
||||
|
||||
enum IntermediateBlockLevelBox<Node> {
|
||||
SameFormattingContextBlock {
|
||||
struct BlockLevelJob<'dom, Node> {
|
||||
node: Node,
|
||||
box_slot: BoxSlot<'dom>,
|
||||
style: Arc<ComputedValues>,
|
||||
contents: IntermediateBlockContainer<Node>,
|
||||
},
|
||||
kind: BlockLevelCreator,
|
||||
}
|
||||
|
||||
enum BlockLevelCreator {
|
||||
SameFormattingContextBlock(IntermediateBlockContainer),
|
||||
Independent {
|
||||
style: Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents<Node>,
|
||||
contents: Contents,
|
||||
},
|
||||
OutOfFlowAbsolutelyPositionedBox {
|
||||
style: Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents<Node>,
|
||||
contents: Contents,
|
||||
},
|
||||
OutOfFlowFloatBox {
|
||||
style: Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents<Node>,
|
||||
contents: Contents,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -67,9 +69,9 @@ enum IntermediateBlockLevelBox<Node> {
|
|||
/// of a given element.
|
||||
///
|
||||
/// Deferring allows using rayon’s `into_par_iter`.
|
||||
enum IntermediateBlockContainer<Node> {
|
||||
enum IntermediateBlockContainer {
|
||||
InlineFormattingContext(InlineFormattingContext),
|
||||
Deferred { contents: NonReplacedContents<Node> },
|
||||
Deferred(NonReplacedContents),
|
||||
}
|
||||
|
||||
/// A builder for a block container.
|
||||
|
@ -79,11 +81,13 @@ enum IntermediateBlockContainer<Node> {
|
|||
struct BlockContainerBuilder<'dom, 'style, Node> {
|
||||
context: &'style LayoutContext<'style>,
|
||||
|
||||
root: Node,
|
||||
|
||||
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
|
||||
/// inline formatting context is not empty, the block container establishes
|
||||
/// 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
|
||||
/// root or there are ongoing inline-level boxes
|
||||
/// (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.
|
||||
///
|
||||
|
@ -131,12 +135,14 @@ struct BlockContainerBuilder<'dom, 'style, Node> {
|
|||
impl BlockContainer {
|
||||
pub fn construct<'dom>(
|
||||
context: &LayoutContext,
|
||||
root: impl NodeExt<'dom>,
|
||||
block_container_style: &Arc<ComputedValues>,
|
||||
contents: NonReplacedContents<impl NodeExt<'dom>>,
|
||||
contents: NonReplacedContents,
|
||||
content_sizes: ContentSizesRequest,
|
||||
) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
|
||||
let mut builder = BlockContainerBuilder {
|
||||
context,
|
||||
root,
|
||||
block_container_style,
|
||||
block_level_boxes: Vec::new(),
|
||||
ongoing_inline_formatting_context: InlineFormattingContext::default(),
|
||||
|
@ -145,7 +151,7 @@ impl BlockContainer {
|
|||
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());
|
||||
|
||||
|
@ -176,15 +182,12 @@ impl BlockContainer {
|
|||
contains_floats: builder.contains_floats,
|
||||
outer_content_sizes_of_children: ContentSizes::zero(),
|
||||
};
|
||||
let mapfold =
|
||||
|acc: &mut Accumulator,
|
||||
(intermediate, box_slot): (IntermediateBlockLevelBox<_>, BoxSlot<'_>)| {
|
||||
let (block_level_box, box_contains_floats) = intermediate.finish(
|
||||
let mapfold = |acc: &mut Accumulator, creator: BlockLevelJob<'dom, _>| {
|
||||
let (block_level_box, box_contains_floats) = creator.finish(
|
||||
context,
|
||||
content_sizes.if_requests_inline(|| &mut acc.outer_content_sizes_of_children),
|
||||
);
|
||||
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 {
|
||||
|
@ -231,15 +234,16 @@ where
|
|||
{
|
||||
fn handle_element(
|
||||
&mut self,
|
||||
node: Node,
|
||||
style: &Arc<ComputedValues>,
|
||||
display: DisplayGeneratingBox,
|
||||
contents: Contents<Node>,
|
||||
contents: Contents,
|
||||
box_slot: BoxSlot<'dom>,
|
||||
) {
|
||||
match display {
|
||||
DisplayGeneratingBox::OutsideInside { outside, inside } => match outside {
|
||||
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 => {
|
||||
let box_style = style.get_box();
|
||||
|
@ -247,22 +251,29 @@ where
|
|||
// https://drafts.csswg.org/css2/visuren.html#dis-pos-flo
|
||||
if box_style.position.is_absolutely_positioned() {
|
||||
self.handle_absolutely_positioned_element(
|
||||
node,
|
||||
style.clone(),
|
||||
inside,
|
||||
contents,
|
||||
box_slot,
|
||||
)
|
||||
} 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 {
|
||||
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);
|
||||
if leading_whitespace || !input.is_empty() {
|
||||
// This text node should be pushed either to the next ongoing
|
||||
|
@ -319,6 +330,7 @@ where
|
|||
if let Some(text) = new_text_run_contents {
|
||||
let parent_style = parent_style.clone();
|
||||
inlines.push(Arc::new(InlineLevelBox::TextRun(TextRun {
|
||||
tag: node.as_opaque(),
|
||||
parent_style,
|
||||
text,
|
||||
})))
|
||||
|
@ -368,15 +380,17 @@ where
|
|||
|
||||
fn handle_inline_level_element(
|
||||
&mut self,
|
||||
node: Node,
|
||||
style: &Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents<Node>,
|
||||
contents: Contents,
|
||||
) -> Arc<InlineLevelBox> {
|
||||
let box_ = if display_inside == DisplayInside::Flow && !contents.is_replaced() {
|
||||
// We found un inline box.
|
||||
// Whatever happened before, all we need to do before recurring
|
||||
// is to remember this ongoing inline level box.
|
||||
self.ongoing_inline_boxes_stack.push(InlineBox {
|
||||
tag: node.as_opaque(),
|
||||
style: style.clone(),
|
||||
first_fragment: true,
|
||||
last_fragment: false,
|
||||
|
@ -384,9 +398,12 @@ where
|
|||
});
|
||||
|
||||
// `unwrap` doesn’t panic here because `is_replaced` returned `false`.
|
||||
NonReplacedContents::try_from(contents)
|
||||
.unwrap()
|
||||
.traverse(&style, self.context, self);
|
||||
NonReplacedContents::try_from(contents).unwrap().traverse(
|
||||
self.context,
|
||||
node,
|
||||
&style,
|
||||
self,
|
||||
);
|
||||
|
||||
let mut inline_box = self
|
||||
.ongoing_inline_boxes_stack
|
||||
|
@ -398,6 +415,7 @@ where
|
|||
Arc::new(InlineLevelBox::Atomic(
|
||||
IndependentFormattingContext::construct(
|
||||
self.context,
|
||||
node,
|
||||
style.clone(),
|
||||
display_inside,
|
||||
contents,
|
||||
|
@ -411,9 +429,10 @@ where
|
|||
|
||||
fn handle_block_level_element(
|
||||
&mut self,
|
||||
node: Node,
|
||||
style: Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents<Node>,
|
||||
contents: Contents,
|
||||
box_slot: BoxSlot<'dom>,
|
||||
) {
|
||||
// We just found a block level element, all ongoing inline level boxes
|
||||
|
@ -427,6 +446,7 @@ where
|
|||
.rev()
|
||||
.map(|ongoing| {
|
||||
let fragmented = InlineBox {
|
||||
tag: ongoing.tag,
|
||||
style: ongoing.style.clone(),
|
||||
first_fragment: ongoing.first_fragment,
|
||||
// The fragmented boxes before the block level element
|
||||
|
@ -459,47 +479,60 @@ where
|
|||
// context needs to be ended.
|
||||
self.end_ongoing_inline_formatting_context();
|
||||
|
||||
let intermediate_box = match contents.try_into() {
|
||||
let kind = match contents.try_into() {
|
||||
Ok(contents) => match display_inside {
|
||||
DisplayInside::Flow => IntermediateBlockLevelBox::SameFormattingContextBlock {
|
||||
style,
|
||||
contents: IntermediateBlockContainer::Deferred { contents },
|
||||
},
|
||||
_ => IntermediateBlockLevelBox::Independent {
|
||||
style,
|
||||
DisplayInside::Flow => BlockLevelCreator::SameFormattingContextBlock(
|
||||
IntermediateBlockContainer::Deferred(contents),
|
||||
),
|
||||
_ => BlockLevelCreator::Independent {
|
||||
display_inside,
|
||||
contents: contents.into(),
|
||||
},
|
||||
},
|
||||
Err(contents) => {
|
||||
let contents = Contents::Replaced(contents);
|
||||
IntermediateBlockLevelBox::Independent {
|
||||
style,
|
||||
BlockLevelCreator::Independent {
|
||||
display_inside,
|
||||
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(
|
||||
&mut self,
|
||||
node: Node,
|
||||
style: Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents<Node>,
|
||||
contents: Contents,
|
||||
box_slot: BoxSlot<'dom>,
|
||||
) {
|
||||
if !self.has_ongoing_inline_formatting_context() {
|
||||
let box_ = IntermediateBlockLevelBox::OutOfFlowAbsolutelyPositionedBox {
|
||||
style,
|
||||
let kind = BlockLevelCreator::OutOfFlowAbsolutelyPositionedBox {
|
||||
contents,
|
||||
display_inside,
|
||||
};
|
||||
self.block_level_boxes.push((box_, box_slot));
|
||||
self.block_level_boxes.push(BlockLevelJob {
|
||||
node,
|
||||
box_slot,
|
||||
style,
|
||||
kind,
|
||||
});
|
||||
} else {
|
||||
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());
|
||||
box_slot.set(LayoutBox::InlineLevel(box_))
|
||||
|
@ -508,23 +541,29 @@ where
|
|||
|
||||
fn handle_float_element(
|
||||
&mut self,
|
||||
node: Node,
|
||||
style: Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents<Node>,
|
||||
contents: Contents,
|
||||
box_slot: BoxSlot<'dom>,
|
||||
) {
|
||||
self.contains_floats = ContainsFloats::Yes;
|
||||
|
||||
if !self.has_ongoing_inline_formatting_context() {
|
||||
let box_ = IntermediateBlockLevelBox::OutOfFlowFloatBox {
|
||||
style,
|
||||
let kind = BlockLevelCreator::OutOfFlowFloatBox {
|
||||
contents,
|
||||
display_inside,
|
||||
};
|
||||
self.block_level_boxes.push((box_, box_slot));
|
||||
self.block_level_boxes.push(BlockLevelJob {
|
||||
node,
|
||||
box_slot,
|
||||
style,
|
||||
kind,
|
||||
});
|
||||
} else {
|
||||
let box_ = Arc::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct(
|
||||
self.context,
|
||||
node,
|
||||
style,
|
||||
display_inside,
|
||||
contents,
|
||||
|
@ -557,13 +596,18 @@ where
|
|||
)
|
||||
});
|
||||
|
||||
let box_ = IntermediateBlockLevelBox::SameFormattingContextBlock {
|
||||
style: anonymous_style.clone(),
|
||||
contents: IntermediateBlockContainer::InlineFormattingContext(std::mem::take(
|
||||
let kind = BlockLevelCreator::SameFormattingContextBlock(
|
||||
IntermediateBlockContainer::InlineFormattingContext(std::mem::take(
|
||||
&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>> {
|
||||
|
@ -582,7 +626,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'dom, Node> IntermediateBlockLevelBox<Node>
|
||||
impl<'dom, Node> BlockLevelJob<'dom, Node>
|
||||
where
|
||||
Node: NodeExt<'dom>,
|
||||
{
|
||||
|
@ -591,10 +635,13 @@ where
|
|||
context: &LayoutContext,
|
||||
max_assign_in_flow_outer_content_sizes_to: Option<&mut ContentSizes>,
|
||||
) -> (Arc<BlockLevelBox>, ContainsFloats) {
|
||||
match self {
|
||||
IntermediateBlockLevelBox::SameFormattingContextBlock { style, contents } => {
|
||||
let node = self.node;
|
||||
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(
|
||||
context,
|
||||
node,
|
||||
&style,
|
||||
ContentSizesRequest::inline_if(
|
||||
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 {
|
||||
to.max_assign(&box_content_sizes.outer_inline(&style))
|
||||
}
|
||||
let block_level_box =
|
||||
Arc::new(BlockLevelBox::SameFormattingContextBlock { contents, style });
|
||||
let block_level_box = Arc::new(BlockLevelBox::SameFormattingContextBlock {
|
||||
tag: node.as_opaque(),
|
||||
contents,
|
||||
style,
|
||||
});
|
||||
(block_level_box, contains_floats)
|
||||
},
|
||||
IntermediateBlockLevelBox::Independent {
|
||||
style,
|
||||
BlockLevelCreator::Independent {
|
||||
display_inside,
|
||||
contents,
|
||||
} => {
|
||||
|
@ -619,6 +668,7 @@ where
|
|||
);
|
||||
let contents = IndependentFormattingContext::construct(
|
||||
context,
|
||||
node,
|
||||
style,
|
||||
display_inside,
|
||||
contents,
|
||||
|
@ -632,43 +682,48 @@ where
|
|||
ContainsFloats::No,
|
||||
)
|
||||
},
|
||||
IntermediateBlockLevelBox::OutOfFlowAbsolutelyPositionedBox {
|
||||
style,
|
||||
BlockLevelCreator::OutOfFlowAbsolutelyPositionedBox {
|
||||
display_inside,
|
||||
contents,
|
||||
} => {
|
||||
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)
|
||||
},
|
||||
IntermediateBlockLevelBox::OutOfFlowFloatBox {
|
||||
style,
|
||||
BlockLevelCreator::OutOfFlowFloatBox {
|
||||
display_inside,
|
||||
contents,
|
||||
} => {
|
||||
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)
|
||||
},
|
||||
}
|
||||
};
|
||||
self.box_slot
|
||||
.set(LayoutBox::BlockLevel(block_level_box.clone()));
|
||||
(block_level_box, contains_floats)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'dom, Node> IntermediateBlockContainer<Node>
|
||||
where
|
||||
Node: NodeExt<'dom>,
|
||||
{
|
||||
fn finish(
|
||||
impl IntermediateBlockContainer {
|
||||
fn finish<'dom>(
|
||||
self,
|
||||
context: &LayoutContext,
|
||||
node: impl NodeExt<'dom>,
|
||||
style: &Arc<ComputedValues>,
|
||||
content_sizes: ContentSizesRequest,
|
||||
) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
|
||||
match self {
|
||||
IntermediateBlockContainer::Deferred { contents } => {
|
||||
BlockContainer::construct(context, style, contents, content_sizes)
|
||||
IntermediateBlockContainer::Deferred(contents) => {
|
||||
BlockContainer::construct(context, node, style, contents, content_sizes)
|
||||
},
|
||||
IntermediateBlockContainer::InlineFormattingContext(ifc) => {
|
||||
let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context));
|
||||
|
|
|
@ -29,14 +29,16 @@ impl FloatContext {
|
|||
impl FloatBox {
|
||||
pub fn construct<'dom>(
|
||||
context: &LayoutContext,
|
||||
node: impl NodeExt<'dom>,
|
||||
style: Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents<impl NodeExt<'dom>>,
|
||||
contents: Contents,
|
||||
) -> Self {
|
||||
let content_sizes = ContentSizesRequest::inline_if(!style.inline_size_is_length());
|
||||
Self {
|
||||
contents: IndependentFormattingContext::construct(
|
||||
context,
|
||||
node,
|
||||
style,
|
||||
display_inside,
|
||||
contents,
|
||||
|
|
|
@ -16,6 +16,7 @@ use crate::ContainingBlock;
|
|||
use app_units::Au;
|
||||
use gfx::text::text_run::GlyphRun;
|
||||
use servo_arc::Arc;
|
||||
use style::dom::OpaqueNode;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{Length, LengthPercentage, Percentage};
|
||||
use style::values::specified::text::TextAlignKeyword;
|
||||
|
@ -38,6 +39,7 @@ pub(crate) enum InlineLevelBox {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct InlineBox {
|
||||
pub tag: OpaqueNode,
|
||||
pub style: Arc<ComputedValues>,
|
||||
pub first_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
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TextRun {
|
||||
pub tag: OpaqueNode,
|
||||
pub parent_style: Arc<ComputedValues>,
|
||||
pub text: String,
|
||||
}
|
||||
|
@ -59,6 +62,7 @@ struct InlineNestingLevelState<'box_tree> {
|
|||
}
|
||||
|
||||
struct PartialInlineBoxFragment<'box_tree> {
|
||||
tag: OpaqueNode,
|
||||
style: Arc<ComputedValues>,
|
||||
start_corner: Vec2<Length>,
|
||||
padding: Sides<Length>,
|
||||
|
@ -371,6 +375,7 @@ impl InlineBox {
|
|||
start_corner += &relative_adjustement(&style, ifc.containing_block)
|
||||
}
|
||||
PartialInlineBoxFragment {
|
||||
tag: self.tag,
|
||||
style,
|
||||
start_corner,
|
||||
padding,
|
||||
|
@ -398,6 +403,7 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
|
|||
at_line_break: bool,
|
||||
) {
|
||||
let mut fragment = BoxFragment {
|
||||
tag: self.tag,
|
||||
style: self.style.clone(),
|
||||
children: std::mem::take(&mut nesting_level.fragments_so_far),
|
||||
content_rect: Rect {
|
||||
|
@ -465,6 +471,7 @@ fn layout_atomic<'box_tree>(
|
|||
let fragments = replaced.make_fragments(&atomic.style, size.clone());
|
||||
let content_rect = Rect { start_corner, size };
|
||||
BoxFragment {
|
||||
tag: atomic.tag,
|
||||
style: atomic.style.clone(),
|
||||
children: fragments,
|
||||
content_rect,
|
||||
|
@ -539,6 +546,7 @@ fn layout_atomic<'box_tree>(
|
|||
},
|
||||
};
|
||||
BoxFragment {
|
||||
tag: atomic.tag,
|
||||
style: atomic.style.clone(),
|
||||
children: independent_layout.fragments,
|
||||
content_rect,
|
||||
|
@ -685,6 +693,7 @@ impl TextRun {
|
|||
ifc.current_nesting_level
|
||||
.fragments_so_far
|
||||
.push(Fragment::Text(TextFragment {
|
||||
tag: self.tag,
|
||||
parent_style: self.parent_style.clone(),
|
||||
rect,
|
||||
ascent: font_ascent.into(),
|
||||
|
|
|
@ -18,6 +18,7 @@ use crate::ContainingBlock;
|
|||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||
use rayon_croissant::ParallelIteratorExt;
|
||||
use servo_arc::Arc;
|
||||
use style::dom::OpaqueNode;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{Length, LengthOrAuto};
|
||||
use style::Zero;
|
||||
|
@ -44,6 +45,7 @@ pub(crate) enum BlockContainer {
|
|||
#[derive(Debug)]
|
||||
pub(crate) enum BlockLevelBox {
|
||||
SameFormattingContextBlock {
|
||||
tag: OpaqueNode,
|
||||
style: Arc<ComputedValues>,
|
||||
contents: BlockContainer,
|
||||
},
|
||||
|
@ -268,8 +270,11 @@ impl BlockLevelBox {
|
|||
float_context: Option<&mut FloatContext>,
|
||||
) -> Fragment {
|
||||
match self {
|
||||
BlockLevelBox::SameFormattingContextBlock { style, contents } => {
|
||||
Fragment::Box(positioning_context.for_maybe_position_relative(
|
||||
BlockLevelBox::SameFormattingContextBlock {
|
||||
tag,
|
||||
style,
|
||||
contents,
|
||||
} => Fragment::Box(positioning_context.for_maybe_position_relative(
|
||||
layout_context,
|
||||
containing_block,
|
||||
style,
|
||||
|
@ -278,14 +283,14 @@ impl BlockLevelBox {
|
|||
layout_context,
|
||||
positioning_context,
|
||||
containing_block,
|
||||
*tag,
|
||||
style,
|
||||
NonReplacedContents::SameFormattingContextBlock(contents),
|
||||
tree_rank,
|
||||
float_context,
|
||||
)
|
||||
},
|
||||
))
|
||||
},
|
||||
)),
|
||||
BlockLevelBox::Independent(contents) => {
|
||||
Fragment::Box(positioning_context.for_maybe_position_relative(
|
||||
layout_context,
|
||||
|
@ -294,6 +299,7 @@ impl BlockLevelBox {
|
|||
|positioning_context| match contents.as_replaced() {
|
||||
Ok(replaced) => layout_in_flow_replaced_block_level(
|
||||
containing_block,
|
||||
contents.tag,
|
||||
&contents.style,
|
||||
replaced,
|
||||
),
|
||||
|
@ -301,6 +307,7 @@ impl BlockLevelBox {
|
|||
layout_context,
|
||||
positioning_context,
|
||||
containing_block,
|
||||
contents.tag,
|
||||
&contents.style,
|
||||
NonReplacedContents::EstablishesAnIndependentFormattingContext(
|
||||
non_replaced,
|
||||
|
@ -339,6 +346,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
|
|||
layout_context: &LayoutContext,
|
||||
positioning_context: &mut PositioningContext<'a>,
|
||||
containing_block: &ContainingBlock,
|
||||
tag: OpaqueNode,
|
||||
style: &Arc<ComputedValues>,
|
||||
block_level_kind: NonReplacedContents<'a>,
|
||||
tree_rank: usize,
|
||||
|
@ -488,6 +496,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
|
|||
},
|
||||
};
|
||||
BoxFragment {
|
||||
tag,
|
||||
style: style.clone(),
|
||||
children: fragments,
|
||||
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
|
||||
fn layout_in_flow_replaced_block_level<'a>(
|
||||
containing_block: &ContainingBlock,
|
||||
tag: OpaqueNode,
|
||||
style: &Arc<ComputedValues>,
|
||||
replaced: &ReplacedContent,
|
||||
) -> BoxFragment {
|
||||
|
@ -536,6 +546,7 @@ fn layout_in_flow_replaced_block_level<'a>(
|
|||
size,
|
||||
};
|
||||
BoxFragment {
|
||||
tag,
|
||||
style: style.clone(),
|
||||
children: fragments,
|
||||
content_rect,
|
||||
|
|
|
@ -61,19 +61,25 @@ fn construct_for_root_element<'dom>(
|
|||
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() {
|
||||
(
|
||||
ContainsFloats::No,
|
||||
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() {
|
||||
(
|
||||
ContainsFloats::Yes,
|
||||
vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(
|
||||
FloatBox::construct(context, style, display_inside, contents),
|
||||
FloatBox::construct(context, root_element, style, display_inside, contents),
|
||||
))],
|
||||
)
|
||||
} else {
|
||||
|
@ -82,6 +88,7 @@ fn construct_for_root_element<'dom>(
|
|||
vec![Arc::new(BlockLevelBox::Independent(
|
||||
IndependentFormattingContext::construct(
|
||||
context,
|
||||
root_element,
|
||||
style,
|
||||
display_inside,
|
||||
contents,
|
||||
|
|
|
@ -13,12 +13,14 @@ use crate::style_ext::DisplayInside;
|
|||
use crate::ContainingBlock;
|
||||
use servo_arc::Arc;
|
||||
use std::convert::TryInto;
|
||||
use style::dom::OpaqueNode;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::Length;
|
||||
|
||||
/// https://drafts.csswg.org/css-display/#independent-formatting-context
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct IndependentFormattingContext {
|
||||
pub tag: OpaqueNode,
|
||||
pub style: Arc<ComputedValues>,
|
||||
|
||||
/// If it was requested during construction
|
||||
|
@ -54,9 +56,10 @@ enum NonReplacedIFCKind<'a> {
|
|||
impl IndependentFormattingContext {
|
||||
pub fn construct<'dom>(
|
||||
context: &LayoutContext,
|
||||
node: impl NodeExt<'dom>,
|
||||
style: Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents<impl NodeExt<'dom>>,
|
||||
contents: Contents,
|
||||
content_sizes: ContentSizesRequest,
|
||||
) -> Self {
|
||||
match contents.try_into() {
|
||||
|
@ -64,11 +67,13 @@ impl IndependentFormattingContext {
|
|||
DisplayInside::Flow | DisplayInside::FlowRoot => {
|
||||
let (bfc, content_sizes) = BlockFormattingContext::construct(
|
||||
context,
|
||||
node,
|
||||
&style,
|
||||
non_replaced,
|
||||
content_sizes,
|
||||
);
|
||||
Self {
|
||||
tag: node.as_opaque(),
|
||||
style,
|
||||
content_sizes,
|
||||
contents: IndependentFormattingContextContents::Flow(bfc),
|
||||
|
@ -78,6 +83,7 @@ impl IndependentFormattingContext {
|
|||
Err(replaced) => {
|
||||
let content_sizes = content_sizes.compute(|| replaced.inline_content_sizes(&style));
|
||||
Self {
|
||||
tag: node.as_opaque(),
|
||||
style,
|
||||
content_sizes,
|
||||
contents: IndependentFormattingContextContents::Replaced(replaced),
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
|||
use gfx::text::glyph::GlyphStore;
|
||||
use servo_arc::Arc as ServoArc;
|
||||
use std::sync::Arc;
|
||||
use style::dom::OpaqueNode;
|
||||
use style::logical_geometry::WritingMode;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::Length;
|
||||
|
@ -20,6 +21,7 @@ pub(crate) enum Fragment {
|
|||
}
|
||||
|
||||
pub(crate) struct BoxFragment {
|
||||
pub tag: OpaqueNode,
|
||||
pub style: ServoArc<ComputedValues>,
|
||||
pub children: Vec<Fragment>,
|
||||
|
||||
|
@ -55,6 +57,7 @@ pub(crate) struct AnonymousFragment {
|
|||
}
|
||||
|
||||
pub(crate) struct TextFragment {
|
||||
pub tag: OpaqueNode,
|
||||
pub parent_style: ServoArc<ComputedValues>,
|
||||
pub rect: Rect<Length>,
|
||||
pub ascent: Length,
|
||||
|
|
|
@ -60,9 +60,10 @@ pub(crate) enum AbsoluteBoxOffsets {
|
|||
impl AbsolutelyPositionedBox {
|
||||
pub fn construct<'dom>(
|
||||
context: &LayoutContext,
|
||||
node: impl NodeExt<'dom>,
|
||||
style: Arc<ComputedValues>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents<impl NodeExt<'dom>>,
|
||||
contents: Contents,
|
||||
) -> Self {
|
||||
// "Shrink-to-fit" in https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
|
||||
let content_sizes = ContentSizesRequest::inline_if(
|
||||
|
@ -76,6 +77,7 @@ impl AbsolutelyPositionedBox {
|
|||
Self {
|
||||
contents: IndependentFormattingContext::construct(
|
||||
context,
|
||||
node,
|
||||
style,
|
||||
display_inside,
|
||||
contents,
|
||||
|
@ -469,6 +471,7 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
|
|||
};
|
||||
|
||||
BoxFragment {
|
||||
tag: self.absolutely_positioned_box.contents.tag,
|
||||
style: style.clone(),
|
||||
children: fragments,
|
||||
content_rect,
|
||||
|
|
|
@ -10,7 +10,7 @@ ${helpers.predefined_type(
|
|||
"cursor",
|
||||
"Cursor",
|
||||
"computed::Cursor::auto()",
|
||||
engines="gecko servo-2013",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
initial_specified_value="specified::Cursor::auto()",
|
||||
animation_value_type="discrete",
|
||||
spec="https://drafts.csswg.org/css-ui/#cursor",
|
||||
|
@ -22,7 +22,7 @@ ${helpers.predefined_type(
|
|||
${helpers.single_keyword(
|
||||
"pointer-events",
|
||||
"auto none",
|
||||
engines="gecko servo-2013",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
animation_value_type="discrete",
|
||||
extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all",
|
||||
spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue