layout: Stop storing PrecomputedStyleData in LayoutNode

Use the SharedStyleContext instead.
This commit is contained in:
Emilio Cobos Álvarez 2016-04-24 18:34:36 +02:00
parent 979c3a54b9
commit 2a499d5a0b
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
15 changed files with 176 additions and 190 deletions

View file

@ -47,6 +47,7 @@ use style::computed_values::content::ContentItem;
use style::computed_values::{caption_side, display, empty_cells, float, list_style_position};
use style::computed_values::{position};
use style::properties::{self, ComputedValues, ServoComputedValues};
use style::servo::SharedStyleContext;
use table::TableFlow;
use table_caption::TableCaptionFlow;
use table_cell::TableCellFlow;
@ -210,15 +211,15 @@ impl InlineFragmentsAccumulator {
}
}
fn from_inline_node<N>(node: &N) -> InlineFragmentsAccumulator
fn from_inline_node<N>(node: &N, style_context: &SharedStyleContext) -> InlineFragmentsAccumulator
where N: ThreadSafeLayoutNode {
InlineFragmentsAccumulator {
fragments: IntermediateInlineFragments::new(),
enclosing_node: Some(InlineFragmentNodeInfo {
address: node.opaque(),
pseudo: node.get_pseudo_element_type().strip(),
style: node.style().clone(),
selected_style: node.selected_style().clone(),
style: node.style(style_context).clone(),
selected_style: node.selected_style(style_context).clone(),
flags: InlineFragmentNodeFlags::empty(),
}),
bidi_control_chars: None,
@ -287,6 +288,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
}
}
#[inline]
fn style_context(&self) -> &SharedStyleContext {
self.layout_context.style_context()
}
#[inline]
fn set_flow_construction_result(&self,
node: &ConcreteThreadSafeLayoutNode,
@ -336,7 +342,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLCanvasElement))) => {
let data = node.canvas_data().unwrap();
SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(node, data))
SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(node, data, self.layout_context))
}
_ => {
// This includes pseudo-elements.
@ -344,7 +350,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
}
};
Fragment::new(node, specific_fragment_info)
Fragment::new(node, specific_fragment_info, self.layout_context)
}
/// Generates anonymous table objects per CSS 2.1 § 17.2.1.
@ -356,13 +362,14 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
return
}
let style_context = self.style_context();
if child.is_table_cell() {
let mut style = child_node.style().clone();
let mut style = child_node.style(style_context).clone();
properties::modify_style_for_anonymous_table_object(&mut style, display::T::table_row);
let fragment = Fragment::from_opaque_node_and_style(child_node.opaque(),
PseudoElementType::Normal,
style,
child_node.selected_style().clone(),
child_node.selected_style(style_context).clone(),
child_node.restyle_damage(),
SpecificFragmentInfo::TableRow);
let mut new_child: FlowRef = Arc::new(TableRowFlow::from_fragment(fragment));
@ -371,12 +378,12 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
*child = new_child
}
if child.is_table_row() || child.is_table_rowgroup() {
let mut style = child_node.style().clone();
let mut style = child_node.style(style_context).clone();
properties::modify_style_for_anonymous_table_object(&mut style, display::T::table);
let fragment = Fragment::from_opaque_node_and_style(child_node.opaque(),
PseudoElementType::Normal,
style,
child_node.selected_style().clone(),
child_node.selected_style(style_context).clone(),
child_node.restyle_damage(),
SpecificFragmentInfo::Table);
let mut new_child: FlowRef = Arc::new(TableFlow::from_fragment(fragment));
@ -385,13 +392,13 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
*child = new_child
}
if child.is_table() {
let mut style = child_node.style().clone();
let mut style = child_node.style(style_context).clone();
properties::modify_style_for_anonymous_table_object(&mut style, display::T::table);
let fragment =
Fragment::from_opaque_node_and_style(child_node.opaque(),
PseudoElementType::Normal,
style,
child_node.selected_style().clone(),
child_node.selected_style(style_context).clone(),
child_node.restyle_damage(),
SpecificFragmentInfo::TableWrapper);
let mut new_child: FlowRef = Arc::new(TableWrapperFlow::from_fragment(fragment, None));
@ -449,7 +456,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
TextRunScanner::new().scan_for_runs(&mut self.layout_context.font_context(),
fragments.fragments);
let mut inline_flow_ref: FlowRef = Arc::new(
InlineFlow::from_fragments(scanned_fragments, node.style().writing_mode));
InlineFlow::from_fragments(scanned_fragments, node.style(self.style_context()).writing_mode));
// Add all the inline-block fragments as children of the inline flow.
for inline_block_flow in &inline_block_flows {
@ -479,7 +486,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let (ascent, descent) =
inline_flow.compute_minimum_ascent_and_descent(&mut self.layout_context
.font_context(),
&**node.style());
&**node.style(self.style_context()));
inline_flow.minimum_block_size_above_baseline = ascent;
inline_flow.minimum_depth_below_baseline = descent;
}
@ -587,10 +594,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
box UnscannedTextFragmentInfo::new(" ".to_owned(), None));
properties::modify_style_for_replaced_content(&mut whitespace_style);
properties::modify_style_for_text(&mut whitespace_style);
let style_context = self.style_context();
let fragment = Fragment::from_opaque_node_and_style(whitespace_node,
whitespace_pseudo,
whitespace_style,
node.selected_style().clone(),
node.selected_style(style_context).clone(),
whitespace_damage,
fragment_info);
inline_fragment_accumulator.fragments.fragments.push_back(fragment);
@ -696,7 +704,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
}
}
let mut style = node.style().clone();
let mut style = node.style(self.style_context()).clone();
if node_is_input_or_text_area {
properties::modify_style_for_input_text(&mut style);
}
@ -722,7 +730,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let mut style = (*style).clone();
properties::modify_style_for_text(&mut style);
let selected_style = node.selected_style();
let selected_style = node.selected_style(self.style_context());
match text_content {
TextContent::Text(string) => {
@ -765,7 +773,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
/// to happen.
fn build_flow_for_block(&mut self, node: &ConcreteThreadSafeLayoutNode, float_kind: Option<FloatKind>)
-> ConstructionResult {
if node.style().is_multicol() {
if node.style(self.style_context()).is_multicol() {
return self.build_flow_for_multicol(node, float_kind)
}
@ -791,7 +799,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
predecessors: mem::replace(
fragment_accumulator,
InlineFragmentsAccumulator::from_inline_node(
node)).to_intermediate_inline_fragments(),
node, self.style_context())).to_intermediate_inline_fragments(),
flow: kid_flow,
};
opt_inline_block_splits.push_back(split)
@ -805,8 +813,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
fn build_fragments_for_nonreplaced_inline_content(&mut self, node: &ConcreteThreadSafeLayoutNode)
-> ConstructionResult {
let mut opt_inline_block_splits: LinkedList<InlineBlockSplit> = LinkedList::new();
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
fragment_accumulator.bidi_control_chars = bidi_control_chars(&*node.style());
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node, self.style_context());
fragment_accumulator.bidi_control_chars = bidi_control_chars(&*node.style(self.style_context()));
let mut abs_descendants = AbsoluteDescendants::new();
@ -828,7 +836,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
mem::replace(
&mut fragment_accumulator,
InlineFragmentsAccumulator::from_inline_node(
node)).to_intermediate_inline_fragments(),
node, self.style_context())).to_intermediate_inline_fragments(),
flow: flow,
};
opt_inline_block_splits.push_back(split);
@ -879,12 +887,13 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
box UnscannedTextFragmentInfo::new(" ".to_owned(), None));
properties::modify_style_for_replaced_content(&mut whitespace_style);
properties::modify_style_for_text(&mut whitespace_style);
let fragment = Fragment::from_opaque_node_and_style(whitespace_node,
whitespace_pseudo,
whitespace_style,
node.selected_style().clone(),
whitespace_damage,
fragment_info);
let fragment =
Fragment::from_opaque_node_and_style(whitespace_node,
whitespace_pseudo,
whitespace_style,
node.selected_style(self.style_context()).clone(),
whitespace_damage,
fragment_info);
fragment_accumulator.fragments.fragments.push_back(fragment)
}
ConstructionResult::ConstructionItem(ConstructionItem::TableColumnFragment(_)) => {
@ -894,17 +903,18 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
}
}
if is_empty && node.style().has_padding_or_border() {
let node_style = node.style(self.style_context());
if is_empty && node_style.has_padding_or_border() {
// An empty inline box needs at least one fragment to draw its background and borders.
let info = SpecificFragmentInfo::UnscannedText(
box UnscannedTextFragmentInfo::new(String::new(), None));
let mut modified_style = node.style().clone();
let mut modified_style = node_style.clone();
properties::modify_style_for_replaced_content(&mut modified_style);
properties::modify_style_for_text(&mut modified_style);
let fragment = Fragment::from_opaque_node_and_style(node.opaque(),
node.get_pseudo_element_type().strip(),
modified_style,
node.selected_style().clone(),
node.selected_style(self.style_context()).clone(),
node.restyle_damage(),
info);
fragment_accumulator.fragments.fragments.push_back(fragment)
@ -917,7 +927,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
// If the node is positioned, then it's the containing block for all absolutely-
// positioned descendants.
if node.style().get_box().position != position::T::static_ {
if node_style.get_box().position != position::T::static_ {
fragment_accumulator.fragments
.absolute_descendants
.mark_as_having_reached_containing_block();
@ -944,17 +954,17 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
}
// If this node is ignorable whitespace, bail out now.
if node.is_ignorable_whitespace() {
if node.is_ignorable_whitespace(self.style_context()) {
return ConstructionResult::ConstructionItem(ConstructionItem::Whitespace(
node.opaque(),
node.get_pseudo_element_type().strip(),
node.style().clone(),
node.style(self.style_context()).clone(),
node.restyle_damage()))
}
// Modify the style as necessary. (See the comment in
// `properties::modify_style_for_replaced_content()`.)
let mut style = (*node.style()).clone();
let mut style = (*node.style(self.style_context())).clone();
properties::modify_style_for_replaced_content(&mut style);
// If this is generated content, then we need to initialize the accumulator with the
@ -987,14 +997,15 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
_ => unreachable!()
};
let mut modified_style = (*node.style()).clone();
let style_context = self.style_context();
let mut modified_style = (*node.style(self.style_context())).clone();
properties::modify_style_for_outer_inline_block_fragment(&mut modified_style);
let fragment_info = SpecificFragmentInfo::InlineBlock(InlineBlockFragmentInfo::new(
block_flow));
let fragment = Fragment::from_opaque_node_and_style(node.opaque(),
node.get_pseudo_element_type().strip(),
modified_style,
node.selected_style().clone(),
node.selected_style(style_context).clone(),
node.restyle_damage(),
fragment_info);
@ -1022,16 +1033,17 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let fragment_info = SpecificFragmentInfo::InlineAbsoluteHypothetical(
InlineAbsoluteHypotheticalFragmentInfo::new(block_flow));
let mut style = node.style().clone();
let style_context = self.style_context();
let mut style = node.style(style_context).clone();
properties::modify_style_for_inline_absolute_hypothetical_fragment(&mut style);
let fragment = Fragment::from_opaque_node_and_style(node.opaque(),
PseudoElementType::Normal,
style,
node.selected_style().clone(),
node.selected_style(style_context).clone(),
node.restyle_damage(),
fragment_info);
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node, self.style_context());
fragment_accumulator.fragments.fragments.push_back(fragment);
fragment_accumulator.fragments.absolute_descendants.push_descendants(abs_descendants);
@ -1087,7 +1099,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
child_flows: Vec<FlowRef>,
flow: &mut FlowRef,
node: &ConcreteThreadSafeLayoutNode) {
let mut anonymous_flow = flow.generate_missing_child_flow(node);
let mut anonymous_flow = flow.generate_missing_child_flow(node, self.layout_context);
let mut consecutive_siblings = vec!();
for kid_flow in child_flows {
if anonymous_flow.need_anonymous_flow(&*kid_flow) {
@ -1115,10 +1127,10 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
fn build_flow_for_multicol(&mut self, node: &ConcreteThreadSafeLayoutNode,
float_kind: Option<FloatKind>)
-> ConstructionResult {
let fragment = Fragment::new(node, SpecificFragmentInfo::Multicol);
let fragment = Fragment::new(node, SpecificFragmentInfo::Multicol, self.layout_context);
let mut flow: FlowRef = Arc::new(MulticolFlow::from_fragment(fragment, float_kind));
let column_fragment = Fragment::new(node, SpecificFragmentInfo::MulticolColumn);
let column_fragment = Fragment::new(node, SpecificFragmentInfo::MulticolColumn, self.layout_context);
let column_flow = Arc::new(MulticolColumnFlow::from_fragment(column_fragment));
// First populate the column flow with its children.
@ -1156,11 +1168,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
/// possibly other `TableCaptionFlow`s or `TableFlow`s underneath it.
fn build_flow_for_table_wrapper(&mut self, node: &ConcreteThreadSafeLayoutNode, float_value: float::T)
-> ConstructionResult {
let fragment = Fragment::new(node, SpecificFragmentInfo::TableWrapper);
let fragment = Fragment::new(node, SpecificFragmentInfo::TableWrapper, self.layout_context);
let mut wrapper_flow: FlowRef = Arc::new(
TableWrapperFlow::from_fragment(fragment, FloatKind::from_property(float_value)));
let table_fragment = Fragment::new(node, SpecificFragmentInfo::Table);
let table_fragment = Fragment::new(node, SpecificFragmentInfo::Table, self.layout_context);
let table_flow = Arc::new(TableFlow::from_fragment(table_fragment));
// First populate the table flow with its children.
@ -1218,7 +1230,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
/// with possibly other `TableRowFlow`s underneath it.
fn build_flow_for_table_rowgroup(&mut self, node: &ConcreteThreadSafeLayoutNode)
-> ConstructionResult {
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow, self.layout_context);
let flow = Arc::new(TableRowGroupFlow::from_fragment(fragment));
self.build_flow_for_block_like(flow, node)
}
@ -1226,7 +1238,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
/// Builds a flow for a node with `display: table-row`. This yields a `TableRowFlow` with
/// possibly other `TableCellFlow`s underneath it.
fn build_flow_for_table_row(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult {
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow, self.layout_context);
let flow = Arc::new(TableRowFlow::from_fragment(fragment));
self.build_flow_for_block_like(flow, node)
}
@ -1234,14 +1246,14 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
/// Builds a flow for a node with `display: table-cell`. This yields a `TableCellFlow` with
/// possibly other `BlockFlow`s or `InlineFlow`s underneath it.
fn build_flow_for_table_cell(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult {
let fragment = Fragment::new(node, SpecificFragmentInfo::TableCell);
let fragment = Fragment::new(node, SpecificFragmentInfo::TableCell, self.layout_context);
// Determine if the table cell should be hidden. Per CSS 2.1 § 17.6.1.1, this will be true
// if the cell has any in-flow elements (even empty ones!) and has `empty-cells` set to
// `hide`.
let hide = node.style().get_inheritedtable().empty_cells == empty_cells::T::hide &&
let hide = node.style(self.style_context()).get_inheritedtable().empty_cells == empty_cells::T::hide &&
node.children().all(|kid| {
let position = kid.style().get_box().position;
let position = kid.style(self.style_context()).get_box().position;
!kid.is_content() ||
position == position::T::absolute ||
position == position::T::fixed
@ -1257,15 +1269,15 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
fn build_flow_for_list_item(&mut self, node: &ConcreteThreadSafeLayoutNode, flotation: float::T)
-> ConstructionResult {
let flotation = FloatKind::from_property(flotation);
let marker_fragments = match node.style().get_list().list_style_image.0 {
let marker_fragments = match node.style(self.style_context()).get_list().list_style_image.0 {
Some(ref url) => {
let image_info = box ImageFragmentInfo::new(node,
Some((*url).clone()),
&self.layout_context);
vec![Fragment::new(node, SpecificFragmentInfo::Image(image_info))]
vec![Fragment::new(node, SpecificFragmentInfo::Image(image_info), self.layout_context)]
}
None => {
match ListStyleTypeContent::from_list_style_type(node.style()
match ListStyleTypeContent::from_list_style_type(node.style(self.style_context())
.get_list()
.list_style_type) {
ListStyleTypeContent::None => Vec::new(),
@ -1275,14 +1287,15 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
unscanned_marker_fragments.push_back(Fragment::new(
node,
SpecificFragmentInfo::UnscannedText(
box UnscannedTextFragmentInfo::new(text, None))));
box UnscannedTextFragmentInfo::new(text, None)),
self.layout_context));
let marker_fragments = TextRunScanner::new().scan_for_runs(
&mut self.layout_context.font_context(),
unscanned_marker_fragments);
marker_fragments.fragments
}
ListStyleTypeContent::GeneratedContent(info) => {
vec![Fragment::new(node, SpecificFragmentInfo::GeneratedContent(info))]
vec![Fragment::new(node, SpecificFragmentInfo::GeneratedContent(info), self.layout_context)]
}
}
}
@ -1295,7 +1308,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
// there.
let mut initial_fragments = IntermediateInlineFragments::new();
let main_fragment = self.build_fragment_for_block(node);
let flow = match node.style().get_list().list_style_position {
let flow = match node.style(self.style_context()).get_list().list_style_position {
list_style_position::T::outside => {
Arc::new(ListItemFlow::from_fragments_and_flotation(
main_fragment, marker_fragments, flotation))
@ -1322,7 +1335,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let specific = SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node));
let construction_item = ConstructionItem::TableColumnFragment(Fragment::new(node,
specific));
specific,
self.layout_context));
ConstructionResult::ConstructionItem(construction_item)
}
@ -1332,7 +1346,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
-> ConstructionResult {
let fragment =
Fragment::new(node,
SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node)));
SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node)),
self.layout_context);
let mut col_fragments = vec!();
for kid in node.children() {
// CSS 2.1 § 17.2.1. Treat all non-column child fragments of `table-column-group`
@ -1345,7 +1360,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
if col_fragments.is_empty() {
debug!("add SpecificFragmentInfo::TableColumn for empty colgroup");
let specific = SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node));
col_fragments.push(Fragment::new(node, specific));
col_fragments.push(Fragment::new(node, specific, self.layout_context));
}
let mut flow: FlowRef = Arc::new(TableColGroupFlow::from_fragments(fragment, col_fragments));
flow.finish();
@ -1387,11 +1402,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
return false
}
if node.can_be_fragmented() || node.style().is_multicol() {
if node.can_be_fragmented() || node.style(self.style_context()).is_multicol() {
return false
}
let mut style = node.style().clone();
let mut style = node.style(self.style_context()).clone();
let mut data = node.mutate_layout_data().unwrap();
let damage = data.restyle_damage;
match *node.construction_result_mut(&mut *data) {
@ -1490,7 +1505,7 @@ impl<'a, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal<ConcreteThreadS
let (display, float, positioning) = match node.type_id() {
None => {
// Pseudo-element.
let style = node.style();
let style = node.style(self.style_context());
let display = match node.get_pseudo_element_type() {
PseudoElementType::Normal => display::T::inline,
PseudoElementType::Before(display) => display,
@ -1501,7 +1516,7 @@ impl<'a, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal<ConcreteThreadS
(display, style.get_box().float, style.get_box().position)
}
Some(NodeTypeId::Element(_)) => {
let style = node.style();
let style = node.style(self.style_context());
let munged_display = if style.get_box()._servo_display_for_hypothetical_box ==
display::T::inline {
display::T::inline

View file

@ -129,6 +129,11 @@ impl<'a> LayoutContext<'a> {
}
}
#[inline(always)]
pub fn style_context(&self) -> &SharedStyleContext {
&self.shared.style_context
}
#[inline(always)]
pub fn font_context(&self) -> RefMut<FontContext> {
self.cached_local_layout_context.font_context.borrow_mut()

View file

@ -4,8 +4,7 @@
use construct::ConstructionResult;
use incremental::RestyleDamage;
use std::sync::Arc;
use style::servo::{PrecomputedStyleData, PrivateStyleData};
use style::servo::PrivateStyleData;
/// Data that layout associates with a node.
pub struct PrivateLayoutData {
@ -37,9 +36,9 @@ pub struct PrivateLayoutData {
impl PrivateLayoutData {
/// Creates new layout data.
pub fn new(precomputed_style_data: Arc<PrecomputedStyleData>) -> PrivateLayoutData {
pub fn new() -> PrivateLayoutData {
PrivateLayoutData {
style_data: PrivateStyleData::new(precomputed_style_data),
style_data: PrivateStyleData::new(),
restyle_damage: RestyleDamage::empty(),
flow_construction_result: ConstructionResult::None,
before_flow_construction_result: ConstructionResult::None,

View file

@ -483,7 +483,7 @@ pub trait ImmutableFlowUtils {
fn need_anonymous_flow(self, child: &Flow) -> bool;
/// Generates missing child flow of this flow.
fn generate_missing_child_flow<N: ThreadSafeLayoutNode>(self, node: &N) -> FlowRef;
fn generate_missing_child_flow<N: ThreadSafeLayoutNode>(self, node: &N, ctx: &LayoutContext) -> FlowRef;
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
fn contains_roots_of_absolute_flow_tree(&self) -> bool;
@ -1275,8 +1275,9 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
/// FIXME(pcwalton): This duplicates some logic in
/// `generate_anonymous_table_flows_if_necessary()`. We should remove this function eventually,
/// as it's harder to understand.
fn generate_missing_child_flow<N: ThreadSafeLayoutNode>(self, node: &N) -> FlowRef {
let mut style = node.style().clone();
fn generate_missing_child_flow<N: ThreadSafeLayoutNode>(self, node: &N, ctx: &LayoutContext) -> FlowRef {
let style_context = ctx.style_context();
let mut style = node.style(style_context).clone();
match self.class() {
FlowClass::Table | FlowClass::TableRowGroup => {
properties::modify_style_for_anonymous_table_object(
@ -1286,7 +1287,7 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
node.opaque(),
PseudoElementType::Normal,
style,
node.selected_style().clone(),
node.selected_style(style_context).clone(),
node.restyle_damage(),
SpecificFragmentInfo::TableRow);
Arc::new(TableRowFlow::from_fragment(fragment))
@ -1299,10 +1300,10 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
node.opaque(),
PseudoElementType::Normal,
style,
node.selected_style().clone(),
node.selected_style(style_context).clone(),
node.restyle_damage(),
SpecificFragmentInfo::TableCell);
let hide = node.style().get_inheritedtable().empty_cells == empty_cells::T::hide;
let hide = node.style(style_context).get_inheritedtable().empty_cells == empty_cells::T::hide;
Arc::new(TableCellFlow::from_node_fragment_and_visibility_flag(node, fragment, !hide))
},
FlowClass::Flex => {
@ -1310,7 +1311,7 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
Fragment::from_opaque_node_and_style(node.opaque(),
PseudoElementType::Normal,
style,
node.selected_style().clone(),
node.selected_style(style_context).clone(),
node.restyle_damage(),
SpecificFragmentInfo::Generic);
Arc::new(BlockFlow::from_fragment(fragment, None))

View file

@ -319,9 +319,9 @@ pub struct CanvasFragmentInfo {
}
impl CanvasFragmentInfo {
pub fn new<N: ThreadSafeLayoutNode>(node: &N, data: HTMLCanvasData) -> CanvasFragmentInfo {
pub fn new<N: ThreadSafeLayoutNode>(node: &N, data: HTMLCanvasData, ctx: &LayoutContext) -> CanvasFragmentInfo {
CanvasFragmentInfo {
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node),
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, ctx),
ipc_renderer: data.ipc_renderer
.map(|renderer| Arc::new(Mutex::new(renderer))),
dom_width: Au::from_px(data.width as i32),
@ -382,7 +382,7 @@ impl ImageFragmentInfo {
};
ImageFragmentInfo {
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node),
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, layout_context),
image: image,
metadata: metadata,
}
@ -441,9 +441,9 @@ pub struct ReplacedImageFragmentInfo {
}
impl ReplacedImageFragmentInfo {
pub fn new<N>(node: &N) -> ReplacedImageFragmentInfo
pub fn new<N>(node: &N, ctx: &LayoutContext) -> ReplacedImageFragmentInfo
where N: ThreadSafeLayoutNode {
let is_vertical = node.style().writing_mode.is_vertical();
let is_vertical = node.style(ctx.style_context()).writing_mode.is_vertical();
ReplacedImageFragmentInfo {
computed_inline_size: None,
computed_block_size: None,
@ -789,8 +789,9 @@ impl TableColumnFragmentInfo {
impl Fragment {
/// Constructs a new `Fragment` instance.
pub fn new<N: ThreadSafeLayoutNode>(node: &N, specific: SpecificFragmentInfo) -> Fragment {
let style = node.style().clone();
pub fn new<N: ThreadSafeLayoutNode>(node: &N, specific: SpecificFragmentInfo, ctx: &LayoutContext) -> Fragment {
let style_context = ctx.style_context();
let style = node.style(style_context).clone();
let writing_mode = style.writing_mode;
let mut restyle_damage = node.restyle_damage();
@ -799,7 +800,7 @@ impl Fragment {
Fragment {
node: node.opaque(),
style: style,
selected_style: node.selected_style().clone(),
selected_style: node.selected_style(style_context).clone(),
restyle_damage: restyle_damage,
border_box: LogicalRect::zero(writing_mode),
border_padding: LogicalMargin::zero(writing_mode),

View file

@ -574,8 +574,8 @@ pub fn process_resolved_style_request<N: LayoutNode>(
let layout_node = match *pseudo {
Some(PseudoElement::Before) => layout_node.get_before_pseudo(),
Some(PseudoElement::After) => layout_node.get_after_pseudo(),
Some(PseudoElement::DetailsSummary) => layout_node.get_details_summary_pseudo(),
Some(PseudoElement::DetailsContent) => layout_node.get_details_content_pseudo(),
Some(PseudoElement::DetailsSummary) |
Some(PseudoElement::DetailsContent) |
Some(PseudoElement::Selection) => None,
_ => Some(layout_node)
};
@ -590,7 +590,7 @@ pub fn process_resolved_style_request<N: LayoutNode>(
Some(layout_node) => layout_node
};
let style = &*layout_node.style();
let style = &*layout_node.resolved_style();
let positioned = match style.get_box().position {
position::computed_value::T::relative |
@ -711,7 +711,7 @@ pub fn process_offset_parent_query<N: LayoutNode>(requested_node: N, layout_root
pub fn process_node_overflow_request<N: LayoutNode>(requested_node: N) -> NodeOverflowResponse {
let layout_node = requested_node.to_threadsafe();
let style = &*layout_node.style();
let style = &*layout_node.resolved_style();
let style_box = style.get_box();
NodeOverflowResponse(Some((Point2D::new(style_box.overflow_x, style_box.overflow_y.0))))
@ -720,7 +720,7 @@ pub fn process_node_overflow_request<N: LayoutNode>(requested_node: N) -> NodeOv
pub fn process_margin_style_query<N: LayoutNode>(requested_node: N)
-> MarginStyleResponse {
let layout_node = requested_node.to_threadsafe();
let style = &*layout_node.style();
let style = &*layout_node.resolved_style();
let margin = style.get_margin();
MarginStyleResponse {

View file

@ -72,7 +72,7 @@ use style::properties::{ComputedValues, ServoComputedValues};
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
use style::restyle_hints::ElementSnapshot;
use style::selector_impl::{NonTSPseudoClass, PseudoElement, ServoSelectorImpl};
use style::servo::{PrecomputedStyleData, PrivateStyleData};
use style::servo::{PrivateStyleData, SharedStyleContext};
use url::Url;
use util::str::is_whitespace;
@ -168,11 +168,11 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() })
}
fn initialize_data(self, precomputed: &Arc<PrecomputedStyleData>) {
fn initialize_data(self) {
let has_data = unsafe { self.borrow_data_unchecked().is_some() };
if !has_data {
let ptr: NonOpaqueStyleAndLayoutData =
Box::into_raw(box RefCell::new(PrivateLayoutData::new(precomputed.clone())));
Box::into_raw(box RefCell::new(PrivateLayoutData::new()));
let opaque = OpaqueStyleAndLayoutData {
ptr: unsafe { NonZero::new(ptr as *mut ()) }
};
@ -428,14 +428,14 @@ impl<'le> TElement for ServoLayoutElement<'le> {
}
#[inline]
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> {
fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str> {
unsafe {
(*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
}
}
#[inline]
fn get_attrs<'a>(&'a self, name: &Atom) -> Vec<&'a str> {
fn get_attrs(&self, name: &Atom) -> Vec<&str> {
unsafe {
(*self.element.unsafe_get()).get_attr_vals_for_layout(name)
}
@ -745,19 +745,12 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
return None;
}
self.borrow_layout_data().unwrap()
.style_data
.precomputed
.computed_values_for(&PseudoElement::DetailsContent,
Some(&*self.style()))
.map(|style| {
let display = if element.get_attr(&ns!(), &atom!("open")).is_some() {
style.get_box().display
} else {
display::T::none
};
self.with_pseudo(PseudoElementType::DetailsContent(display))
})
let display = if element.get_attr(&ns!(), &atom!("open")).is_some() {
display::T::block
} else {
display::T::none
};
Some(self.with_pseudo(PseudoElementType::DetailsContent(display)))
}
/// Borrows the layout data immutably. Fails on a conflicting borrow.
@ -777,7 +770,7 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
///
/// Unlike the version on TNode, this handles pseudo-elements.
#[inline]
fn style(&self) -> Ref<Arc<ServoComputedValues>> {
fn style(&self, context: &SharedStyleContext) -> Ref<Arc<ServoComputedValues>> {
match self.get_pseudo_element_type() {
PseudoElementType::Normal => {
Ref::map(self.borrow_layout_data().unwrap(), |data| {
@ -791,10 +784,9 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
if !style_pseudo.is_eagerly_cascaded() &&
!self.borrow_layout_data().unwrap().style_data.per_pseudo.contains_key(&style_pseudo) {
let mut data = self.mutate_layout_data().unwrap();
let new_style = data.style_data
.precomputed
.computed_values_for(&style_pseudo,
data.style_data.style.as_ref());
let new_style = context.stylist
.computed_values_for_pseudo(&style_pseudo,
data.style_data.style.as_ref());
data.style_data.per_pseudo.insert(style_pseudo.clone(), new_style.unwrap());
}
@ -805,8 +797,26 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
}
}
/// Returns the already resolved style of the node.
///
/// This differs from `style(ctx)` in that if the pseudo-element has not yet
/// been computed it would panic.
///
/// This should be used just for querying layout, not from layout itself.
#[inline]
fn selected_style(&self) -> Ref<Arc<ServoComputedValues>> {
fn resolved_style(&self) -> Ref<Arc<ServoComputedValues>> {
Ref::map(self.borrow_layout_data().unwrap(), |data| {
match self.get_pseudo_element_type() {
PseudoElementType::Normal
=> data.style_data.style.as_ref().unwrap(),
other
=> data.style_data.per_pseudo.get(&other.style_pseudo_element()).unwrap(),
}
})
}
#[inline]
fn selected_style(&self, _context: &SharedStyleContext) -> Ref<Arc<ServoComputedValues>> {
Ref::map(self.borrow_layout_data().unwrap(), |data| {
data.style_data.per_pseudo
.get(&PseudoElement::Selection)
@ -830,7 +840,7 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
};
}
fn is_ignorable_whitespace(&self) -> bool;
fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool;
fn restyle_damage(self) -> RestyleDamage;
@ -909,7 +919,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized {
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>;
#[inline]
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str>;
fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str>;
#[inline]
fn get_local_name(&self) -> &Atom;
@ -1030,7 +1040,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
self.node.mutate_layout_data()
}
fn is_ignorable_whitespace(&self) -> bool {
fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool {
unsafe {
let text: LayoutJS<Text> = match self.get_jsmanaged().downcast() {
Some(text) => text,
@ -1047,7 +1057,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
//
// If you implement other values for this property, you will almost certainly
// want to update this check.
!self.style().get_inheritedtext().white_space.preserve_newlines()
!self.style(context).get_inheritedtext().white_space.preserve_newlines()
}
}

View file

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use properties::ComputedValues;
use selector_matching::PrecomputedStyleData;
use selectors::parser::SelectorImpl;
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
@ -14,12 +13,6 @@ pub struct PrivateStyleData<Impl: SelectorImpl, ConcreteComputedValues: Computed
/// The results of CSS styling for this node.
pub style: Option<Arc<ConcreteComputedValues>>,
/// Shared rules data needed to avoid doing the cascade for some
/// pseudo-elements like "-servo-details-content"
///
/// TODO: Move to TLS to avoid this extra pointer?
pub precomputed: Arc<PrecomputedStyleData<Impl, ConcreteComputedValues>>,
/// The results of CSS styling for each pseudo-element (if any).
pub per_pseudo: HashMap<Impl::PseudoElement, Arc<ConcreteComputedValues>,
BuildHasherDefault<::fnv::FnvHasher>>,
@ -30,11 +23,9 @@ pub struct PrivateStyleData<Impl: SelectorImpl, ConcreteComputedValues: Computed
impl<Impl, ConcreteComputedValues> PrivateStyleData<Impl, ConcreteComputedValues>
where Impl: SelectorImpl, ConcreteComputedValues: ComputedValues {
pub fn new(precomputed: Arc<PrecomputedStyleData<Impl, ConcreteComputedValues>>)
-> PrivateStyleData<Impl, ConcreteComputedValues> {
pub fn new() -> PrivateStyleData<Impl, ConcreteComputedValues> {
PrivateStyleData {
style: None,
precomputed: precomputed,
per_pseudo: HashMap::with_hasher(Default::default()),
parallel: DomParallelInfo::new(),
}

View file

@ -4,12 +4,12 @@
#![allow(unsafe_code)]
use context::SharedStyleContext;
use data::PrivateStyleData;
use element_state::ElementState;
use properties::{ComputedValues, PropertyDeclaration, PropertyDeclarationBlock};
use restyle_hints::{ElementSnapshot, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
use selector_impl::{ElementExt, SelectorImplExt};
use selector_matching::PrecomputedStyleData;
use selectors::Element;
use selectors::matching::DeclarationBlock;
use smallvec::VecLike;
@ -90,10 +90,7 @@ pub trait TNode : Sized + Copy + Clone {
/// initialized.
///
/// FIXME(pcwalton): Do this as part of fragment building instead of in a traversal.
fn initialize_data(self,
precomputed: &Arc<PrecomputedStyleData<<Self::ConcreteElement as Element>::Impl,
Self::ConcreteComputedValues>>)
where <Self::ConcreteElement as Element>::Impl: SelectorImplExt;
fn initialize_data(self);
/// While doing a reflow, the node at the root has no parent, as far as we're
/// concerned. This method returns `None` at the reflow root.
@ -174,7 +171,10 @@ pub trait TNode : Sized + Copy + Clone {
/// Returns the style results for the given node. If CSS selector matching
/// has not yet been performed, fails.
fn style(&self) -> Ref<Arc<Self::ConcreteComputedValues>> {
fn style(&self,
_context: &SharedStyleContext<<Self::ConcreteElement as Element>::Impl>)
-> Ref<Arc<Self::ConcreteComputedValues>>
where <Self::ConcreteElement as Element>::Impl: SelectorImplExt<ComputedValues=Self::ConcreteComputedValues> {
Ref::map(self.borrow_data().unwrap(), |data| data.style.as_ref().unwrap())
}

View file

@ -2,11 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use element_state::ElementState;
use properties::{self, ServoComputedValues};
use selector_matching::{USER_OR_USER_AGENT_STYLESHEETS, QUIRKS_MODE_STYLESHEET};
use selectors::Element;
use selectors::parser::{ParserContext, SelectorImpl};
use stylesheets::Stylesheet;
use properties::{self, ServoComputedValues};
pub trait ElementExt: Element {
fn is_link(&self) -> bool;

View file

@ -84,42 +84,6 @@ lazy_static! {
};
}
#[derive(HeapSizeOf)]
pub struct PrecomputedStyleData<Impl: SelectorImpl, Computed: ComputedValues> {
/// Applicable declarations for a given non-eagerly cascaded pseudo-element.
/// These are eagerly computed once, and then used to resolve the new
/// computed values on the fly on layout.
non_eagerly_cascaded_pseudo_elements: HashMap<Impl::PseudoElement,
Vec<DeclarationBlock>,
BuildHasherDefault<::fnv::FnvHasher>>,
_phantom: ::std::marker::PhantomData<Computed>,
}
impl<Impl, Computed> PrecomputedStyleData<Impl, Computed>
where Impl: SelectorImpl, Computed: ComputedValues {
fn new() -> Self {
PrecomputedStyleData {
non_eagerly_cascaded_pseudo_elements: HashMap::with_hasher(Default::default()),
_phantom: ::std::marker::PhantomData,
}
}
pub fn computed_values_for(&self,
pseudo: &Impl::PseudoElement,
parent: Option<&Arc<Computed>>) -> Option<Arc<Computed>> {
if let Some(declarations) = self.non_eagerly_cascaded_pseudo_elements.get(pseudo) {
let (computed, _) =
properties::cascade::<Computed>(Size2D::zero(),
&declarations, false,
parent.map(|p| &**p), None,
box StdoutErrorReporter);
Some(Arc::new(computed))
} else {
parent.map(|p| p.clone())
}
}
}
/// This structure holds all the selectors and device characteristics
/// for a given document. The selectors are converted into `Rule`s
/// (defined in rust-selectors), and introduced in a `SelectorMap`
@ -160,10 +124,12 @@ pub struct Stylist<Impl: SelectorImplExt> {
PerPseudoElementSelectorMap<Impl>,
BuildHasherDefault<::fnv::FnvHasher>>,
/// Precomputed data to be shared to the nodes.
/// Note that this has to be an Arc, since the layout thread needs the
/// stylist mutable.
precomputed: Arc<PrecomputedStyleData<Impl, Impl::ComputedValues>>,
/// Applicable declarations for a given non-eagerly cascaded pseudo-element.
/// These are eagerly computed once, and then used to resolve the new
/// computed values on the fly on layout.
non_eagerly_cascaded_pseudo_element_decls: HashMap<Impl::PseudoElement,
Vec<DeclarationBlock>,
BuildHasherDefault<::fnv::FnvHasher>>,
rules_source_order: usize,
@ -182,7 +148,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
element_map: PerPseudoElementSelectorMap::new(),
pseudos_map: HashMap::with_hasher(Default::default()),
precomputed: Arc::new(PrecomputedStyleData::new()),
non_eagerly_cascaded_pseudo_element_decls: HashMap::with_hasher(Default::default()),
rules_source_order: 0,
state_deps: DependencySet::new(),
};
@ -205,7 +171,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
self.element_map = PerPseudoElementSelectorMap::new();
self.pseudos_map = HashMap::with_hasher(Default::default());
self.precomputed = Arc::new(PrecomputedStyleData::new());
self.non_eagerly_cascaded_pseudo_element_decls = HashMap::with_hasher(Default::default());
self.rules_source_order = 0;
self.state_deps.clear();
@ -279,29 +245,30 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
// This is actually kind of hard, because the stylist is shared
// between threads.
if let Some(map) = self.pseudos_map.remove(&pseudo) {
let mut precomputed = Arc::get_mut(&mut self.precomputed)
.expect("Stylist was not the single owner of PrecomputedStyleData");
let mut declarations = vec![];
map.user_agent.normal.get_universal_rules(&mut declarations);
map.user_agent.important.get_universal_rules(&mut declarations);
precomputed.non_eagerly_cascaded_pseudo_elements.insert(pseudo, declarations);
self.non_eagerly_cascaded_pseudo_element_decls.insert(pseudo, declarations);
}
})
}
pub fn get_precomputed_data(&self) -> &Arc<PrecomputedStyleData<Impl, Impl::ComputedValues>> {
&self.precomputed
}
pub fn get_non_eagerly_cascaded_pseudo_element_style(&self,
pseudo: &Impl::PseudoElement,
parent: Option<&Arc<Impl::ComputedValues>>) -> Option<Arc<Impl::ComputedValues>> {
pub fn computed_values_for_pseudo(&self,
pseudo: &Impl::PseudoElement,
parent: Option<&Arc<Impl::ComputedValues>>) -> Option<Arc<Impl::ComputedValues>> {
debug_assert!(!Impl::is_eagerly_cascaded_pseudo_element(pseudo));
self.precomputed
.computed_values_for(pseudo, parent)
if let Some(declarations) = self.non_eagerly_cascaded_pseudo_element_decls.get(pseudo) {
let (computed, _) =
properties::cascade::<Impl::ComputedValues>(Size2D::zero(),
&declarations, false,
parent.map(|p| &**p), None,
box StdoutErrorReporter);
Some(Arc::new(computed))
} else {
parent.map(|p| p.clone())
}
}
pub fn compute_restyle_hint<E>(&self, element: &E,

View file

@ -11,6 +11,5 @@ use stylesheets;
/// Concrete types for servo Style implementation
pub type Stylesheet = stylesheets::Stylesheet<ServoSelectorImpl>;
pub type PrivateStyleData = data::PrivateStyleData<ServoSelectorImpl, ServoComputedValues>;
pub type PrecomputedStyleData = selector_matching::PrecomputedStyleData<ServoSelectorImpl, ServoComputedValues>;
pub type Stylist = selector_matching::Stylist<ServoSelectorImpl>;
pub type SharedStyleContext = context::SharedStyleContext<ServoSelectorImpl>;

View file

@ -129,7 +129,7 @@ pub fn recalc_style_at<'a, N, C>(context: &'a C,
//
// FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML
// parser.
node.initialize_data(context.shared_context().stylist.get_precomputed_data());
node.initialize_data();
// Get the parent node.
let parent_opt = node.layout_parent_node(root);

View file

@ -54,7 +54,6 @@ details[open]::-servo-details-summary {
*|*::-servo-details-content {
margin-left: 40px;
overflow: hidden;
display: block;
}
/*
* Until servo supports svg properly, make sure to at least prevent svg

View file

@ -6,4 +6,3 @@
<summary>Test</summary>
Contents
</details>