From f9cdd05d58e7f1a8cd6198dad3058d86bf479a08 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 5 Mar 2015 12:37:37 -0800 Subject: =?UTF-8?q?layout:=20Implement=20ordered=20lists,=20CSS=20counters?= =?UTF-8?q?,=20and=20`quotes`=20per=20CSS=202.1=20=C2=A7=2012.3-12.5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only simple alphabetic and numeric counter styles are supported. (This is most of them though.) Although this PR adds a sequential pass to layout, I verified that on pages that contain a reasonable number of ordered lists (Reddit `/r/rust`), the time spent in generated content resolution is dwarfed by the time spent in the parallelizable parts of layout. So I don't expect this to negatively affect our parallelism expect perhaps in pathological cases. --- components/layout/construct.rs | 326 +++++++++++++++++++++++------------------ 1 file changed, 181 insertions(+), 145 deletions(-) (limited to 'components/layout/construct.rs') diff --git a/components/layout/construct.rs b/components/layout/construct.rs index b8dd5a8415e..b29b6507c2d 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -16,23 +16,23 @@ use block::BlockFlow; use context::LayoutContext; use css::node_style::StyledNode; +use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataAccess, LayoutDataWrapper}; use floats::FloatKind; use flow::{Descendants, AbsDescendants}; use flow::{Flow, ImmutableFlowUtils, MutableOwnedFlowUtils}; use flow::{IS_ABSOLUTELY_POSITIONED}; use flow; use flow_ref::FlowRef; +use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo}; use fragment::CanvasFragmentInfo; use fragment::ImageFragmentInfo; use fragment::InlineAbsoluteHypotheticalFragmentInfo; use fragment::TableColumnFragmentInfo; use fragment::UnscannedTextFragmentInfo; -use fragment::{Fragment, IframeFragmentInfo}; use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo}; use incremental::{RECONSTRUCT_FLOW, RestyleDamage}; use inline::InlineFlow; -use data::{HAS_NEWLY_CONSTRUCTED_FLOW, LayoutDataAccess, LayoutDataWrapper}; -use list_item::{self, ListItemFlow}; +use list_item::{ListItemFlow, ListStyleTypeContent}; use opaque_node::OpaqueNodeMethods; use parallel; use table::TableFlow; @@ -55,9 +55,10 @@ use std::borrow::ToOwned; use std::collections::DList; use std::mem; use std::sync::atomic::Ordering; +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::{ComputedValues, make_inline}; +use style::properties::{self, ComputedValues}; use std::sync::Arc; use url::Url; @@ -265,41 +266,51 @@ impl<'a> FlowConstructor<'a> { } } - /// Builds specific `Fragment` info for the given node. - /// - /// This does *not* construct the text for generated content (but, for generated content with - /// `display: block`, it does construct the generic fragment corresponding to the block). - /// Construction of the text fragment is done specially by `build_flow_using_children()` and - /// `build_fragments_for_replaced_inline_content()`. - pub fn build_specific_fragment_info_for_node(&mut self, node: &ThreadSafeLayoutNode) - -> SpecificFragmentInfo { - match node.type_id() { - Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement))) => { + /// Builds the fragment for the given block or subclass thereof. + fn build_fragment_for_block(&mut self, node: &ThreadSafeLayoutNode) -> Fragment { + let specific_fragment_info = match node.type_id() { + Some(NodeTypeId::Element(ElementTypeId::HTMLElement( + HTMLElementTypeId::HTMLIFrameElement))) => { SpecificFragmentInfo::Iframe(box IframeFragmentInfo::new(node)) } - Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement))) => { + Some(NodeTypeId::Element(ElementTypeId::HTMLElement( + HTMLElementTypeId::HTMLImageElement))) => { self.build_fragment_info_for_image(node, node.image_url()) } - Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement))) => { + Some(NodeTypeId::Element(ElementTypeId::HTMLElement( + HTMLElementTypeId::HTMLObjectElement))) => { let data = node.get_object_data(); self.build_fragment_info_for_image(node, data) } - Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement))) => SpecificFragmentInfo::TableWrapper, - Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement))) => { + Some(NodeTypeId::Element(ElementTypeId::HTMLElement( + HTMLElementTypeId::HTMLTableElement))) => { + SpecificFragmentInfo::TableWrapper + } + Some(NodeTypeId::Element(ElementTypeId::HTMLElement( + HTMLElementTypeId::HTMLTableColElement))) => { SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node)) } - Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableCellElement(_)))) => SpecificFragmentInfo::TableCell, - Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement))) | - Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement))) => SpecificFragmentInfo::TableRow, - Some(NodeTypeId::Text) => SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::new(node)), - Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement))) => { + Some(NodeTypeId::Element(ElementTypeId::HTMLElement( + HTMLElementTypeId::HTMLTableCellElement(_)))) => { + SpecificFragmentInfo::TableCell + } + Some(NodeTypeId::Element(ElementTypeId::HTMLElement( + HTMLElementTypeId::HTMLTableRowElement))) | + Some(NodeTypeId::Element(ElementTypeId::HTMLElement( + HTMLElementTypeId::HTMLTableSectionElement))) => { + SpecificFragmentInfo::TableRow + } + Some(NodeTypeId::Element(ElementTypeId::HTMLElement( + HTMLElementTypeId::HTMLCanvasElement))) => { SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(node)) } _ => { // This includes pseudo-elements. SpecificFragmentInfo::Generic } - } + }; + + Fragment::new(node, specific_fragment_info) } /// Creates an inline flow from a set of inline fragments, then adds it as a child of the given @@ -339,7 +350,9 @@ impl<'a> FlowConstructor<'a> { let mut inline_block_flows = vec!(); for f in fragments.iter() { match f.specific { - SpecificFragmentInfo::InlineBlock(ref info) => inline_block_flows.push(info.flow_ref.clone()), + SpecificFragmentInfo::InlineBlock(ref info) => { + inline_block_flows.push(info.flow_ref.clone()) + } SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => { inline_block_flows.push(info.flow_ref.clone()) } @@ -473,8 +486,8 @@ impl<'a> FlowConstructor<'a> { whitespace_damage)) => { // Add whitespace results. They will be stripped out later on when // between block elements, and retained when between inline elements. - let fragment_info = - SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::from_text(" ".to_owned())); + let fragment_info = SpecificFragmentInfo::UnscannedText( + UnscannedTextFragmentInfo::from_text(" ".to_owned())); let fragment = Fragment::from_opaque_node_and_style(whitespace_node, whitespace_style, whitespace_damage, @@ -488,25 +501,20 @@ impl<'a> FlowConstructor<'a> { } } - /// Constructs a block flow, beginning with the given `initial_fragment` if present and then + /// Constructs a block flow, beginning with the given `initial_fragments` if present and then /// appending the construction results of children to the child list of the block flow. {ib} /// splits and absolutely-positioned descendants are handled correctly. - fn build_flow_for_block_starting_with_fragment(&mut self, - mut flow: FlowRef, - node: &ThreadSafeLayoutNode, - initial_fragment: Option) - -> ConstructionResult { + fn build_flow_for_block_starting_with_fragments(&mut self, + mut flow: FlowRef, + node: &ThreadSafeLayoutNode, + mut initial_fragments: DList) + -> ConstructionResult { // Gather up fragments for the inline flows we might need to create. let mut inline_fragment_accumulator = InlineFragmentsAccumulator::new(); let mut consecutive_siblings = vec!(); - let mut first_fragment = match initial_fragment { - None => true, - Some(initial_fragment) => { - inline_fragment_accumulator.fragments.push_back(initial_fragment); - false - } - }; + inline_fragment_accumulator.fragments.append(&mut initial_fragments); + let mut first_fragment = inline_fragment_accumulator.fragments.is_empty(); // List of absolute descendants, in tree order. let mut abs_descendants = Descendants::new(); @@ -558,7 +566,7 @@ impl<'a> FlowConstructor<'a> { /// Constructs a flow for the given block node and its children. This method creates an /// initial fragment as appropriate and then dispatches to - /// `build_flow_for_block_starting_with_fragment`. Currently the following kinds of flows get + /// `build_flow_for_block_starting_with_fragments`. Currently the following kinds of flows get /// initial content: /// /// * Generated content gets the initial content specified by the `content` attribute of the @@ -569,32 +577,60 @@ impl<'a> FlowConstructor<'a> { /// `