diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2014-02-05 19:12:02 -0800 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2014-02-06 09:34:14 -0800 |
commit | 18c025a8eda4f648a6534e917e3786d484cb5b8e (patch) | |
tree | fb71120f38346595d69f06e1b01d28f31c43a365 /src | |
parent | 17bc467b834f72612a9b8ae4d76f5b67a567fd46 (diff) | |
download | servo-18c025a8eda4f648a6534e917e3786d484cb5b8e.tar.gz servo-18c025a8eda4f648a6534e917e3786d484cb5b8e.zip |
layout: Lazily create boxes for whitespace, speculating that they won't
be needed.
33% win in flow construction on the rainbow page.
Diffstat (limited to 'src')
-rw-r--r-- | src/components/main/layout/box_.rs | 27 | ||||
-rw-r--r-- | src/components/main/layout/construct.rs | 58 |
2 files changed, 83 insertions, 2 deletions
diff --git a/src/components/main/layout/box_.rs b/src/components/main/layout/box_.rs index f4d694e9f99..71189b60c34 100644 --- a/src/components/main/layout/box_.rs +++ b/src/components/main/layout/box_.rs @@ -256,6 +256,14 @@ impl UnscannedTextBoxInfo { text: node.text(), } } + + /// Creates a new instance of `UnscannedTextBoxInfo` from the given text. + #[inline] + pub fn from_text(text: ~str) -> UnscannedTextBoxInfo { + UnscannedTextBoxInfo { + text: text, + } + } } /// Represents the outcome of attempting to split a box. @@ -313,6 +321,25 @@ impl Box { } } + /// Constructs a new `Box` instance from an opaque node. + pub fn from_opaque_node_and_style(node: OpaqueNode, + style: Arc<ComputedValues>, + specific: SpecificBoxInfo) + -> Box { + Box { + node: node, + style: style, + position: RefCell::new(Au::zero_rect()), + border: RefCell::new(Zero::zero()), + padding: RefCell::new(Zero::zero()), + margin: RefCell::new(Zero::zero()), + specific: specific, + position_offsets: RefCell::new(Zero::zero()), + inline_info: RefCell::new(None), + new_line_pos: ~[], + } + } + /// Returns a debug ID of this box. This ID should not be considered stable across multiple /// layouts or box manipulations. pub fn debug_id(&self) -> uint { diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs index 338c401ef27..2d82a9c3810 100644 --- a/src/components/main/layout/construct.rs +++ b/src/components/main/layout/construct.rs @@ -37,8 +37,10 @@ use gfx::font_context::FontContext; use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId}; use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId}; use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, TextNodeTypeId}; -use style::computed_values::{display, position, float}; +use style::computed_values::{display, position, float, white_space}; +use style::ComputedValues; +use extra::arc::Arc; use std::cell::RefCell; use std::util; use std::num::Zero; @@ -74,6 +76,8 @@ impl ConstructionResult { enum ConstructionItem { /// Inline boxes and associated {ib} splits that have not yet found flows. InlineBoxesConstructionItem(InlineBoxesConstructionResult), + /// Potentially ignorable whitespace. + WhitespaceConstructionItem(OpaqueNode, Arc<ComputedValues>), } impl ConstructionItem { @@ -86,6 +90,7 @@ impl ConstructionItem { } } } + WhitespaceConstructionItem(..) => {} } } } @@ -369,6 +374,9 @@ impl<'fc> FlowConstructor<'fc> { // Add the boxes to the list we're maintaining. opt_boxes_for_inline_flow.push_all_move(boxes) } + ConstructionItemConstructionResult(WhitespaceConstructionItem(..)) => { + // Nothing to do here. + } } } @@ -457,6 +465,15 @@ impl<'fc> FlowConstructor<'fc> { // Push residual boxes. opt_box_accumulator.push_all_move(boxes) } + ConstructionItemConstructionResult(WhitespaceConstructionItem(whitespace_node, + whitespace_style)) + => { + // Instantiate the whitespace box. + opt_box_accumulator.push(Box::from_opaque_node_and_style( + whitespace_node, + whitespace_style, + UnscannedTextBox(UnscannedTextBoxInfo::from_text(~" ")))) + } } } @@ -570,6 +587,14 @@ impl<'fc> FlowConstructor<'fc> { kid.set_flow_construction_result(NoConstructionResult) } + // If this node is ignorable whitespace, bail out now. + if node.is_ignorable_whitespace() { + let opaque_node = OpaqueNode::from_thread_safe_layout_node(&node); + return ConstructionItemConstructionResult(WhitespaceConstructionItem( + opaque_node, + node.style().clone())) + } + let construction_item = InlineBoxesConstructionItem(InlineBoxesConstructionResult { splits: None, boxes: ~[ @@ -628,7 +653,6 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> { (display::inline, float::none, _) => { let construction_result = self.build_boxes_for_inline(node); node.set_flow_construction_result(construction_result) - } // Block flows that are not floated contribute block flow construction results. @@ -662,6 +686,9 @@ trait NodeUtils { /// Returns true if this node doesn't render its kids and false otherwise. fn is_replaced_content(self) -> bool; + /// Returns true if this node is ignorable whitespace. + fn is_ignorable_whitespace(self) -> bool; + /// Sets the construction result of a flow. fn set_flow_construction_result(self, result: ConstructionResult); @@ -683,6 +710,33 @@ impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> { } } + fn is_ignorable_whitespace(self) -> bool { + match self.type_id() { + TextNodeTypeId => { + unsafe { + if !self.with_text(|text| text.element + .data + .chars() + .all(|c| c.is_whitespace())) { + return false + } + + // NB: See the rules for `white-space` here: + // + // http://www.w3.org/TR/CSS21/text.html#propdef-white-space + // + // If you implement other values for this property, you will almost certainly + // want to update this check. + match self.style().get().Text.white_space { + white_space::normal => true, + _ => false, + } + } + } + _ => false + } + } + #[inline(always)] fn set_flow_construction_result(self, result: ConstructionResult) { let mut layout_data_ref = self.mutate_layout_data(); |