mirror of
https://github.com/servo/servo.git
synced 2025-06-20 07:08:59 +01:00
layout: Lazily create boxes for whitespace, speculating that they won't
be needed. 33% win in flow construction on the rainbow page.
This commit is contained in:
parent
17bc467b83
commit
18c025a8ed
2 changed files with 83 additions and 2 deletions
|
@ -256,6 +256,14 @@ impl UnscannedTextBoxInfo {
|
||||||
text: node.text(),
|
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.
|
/// 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
|
/// Returns a debug ID of this box. This ID should not be considered stable across multiple
|
||||||
/// layouts or box manipulations.
|
/// layouts or box manipulations.
|
||||||
pub fn debug_id(&self) -> uint {
|
pub fn debug_id(&self) -> uint {
|
||||||
|
|
|
@ -37,8 +37,10 @@ use gfx::font_context::FontContext;
|
||||||
use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId};
|
use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId};
|
||||||
use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
|
use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
|
||||||
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, TextNodeTypeId};
|
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::cell::RefCell;
|
||||||
use std::util;
|
use std::util;
|
||||||
use std::num::Zero;
|
use std::num::Zero;
|
||||||
|
@ -74,6 +76,8 @@ impl ConstructionResult {
|
||||||
enum ConstructionItem {
|
enum ConstructionItem {
|
||||||
/// Inline boxes and associated {ib} splits that have not yet found flows.
|
/// Inline boxes and associated {ib} splits that have not yet found flows.
|
||||||
InlineBoxesConstructionItem(InlineBoxesConstructionResult),
|
InlineBoxesConstructionItem(InlineBoxesConstructionResult),
|
||||||
|
/// Potentially ignorable whitespace.
|
||||||
|
WhitespaceConstructionItem(OpaqueNode, Arc<ComputedValues>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstructionItem {
|
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.
|
// Add the boxes to the list we're maintaining.
|
||||||
opt_boxes_for_inline_flow.push_all_move(boxes)
|
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.
|
// Push residual boxes.
|
||||||
opt_box_accumulator.push_all_move(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)
|
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 {
|
let construction_item = InlineBoxesConstructionItem(InlineBoxesConstructionResult {
|
||||||
splits: None,
|
splits: None,
|
||||||
boxes: ~[
|
boxes: ~[
|
||||||
|
@ -628,7 +653,6 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
|
||||||
(display::inline, float::none, _) => {
|
(display::inline, float::none, _) => {
|
||||||
let construction_result = self.build_boxes_for_inline(node);
|
let construction_result = self.build_boxes_for_inline(node);
|
||||||
node.set_flow_construction_result(construction_result)
|
node.set_flow_construction_result(construction_result)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block flows that are not floated contribute block flow construction results.
|
// 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.
|
/// Returns true if this node doesn't render its kids and false otherwise.
|
||||||
fn is_replaced_content(self) -> bool;
|
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.
|
/// Sets the construction result of a flow.
|
||||||
fn set_flow_construction_result(self, result: ConstructionResult);
|
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)]
|
#[inline(always)]
|
||||||
fn set_flow_construction_result(self, result: ConstructionResult) {
|
fn set_flow_construction_result(self, result: ConstructionResult) {
|
||||||
let mut layout_data_ref = self.mutate_layout_data();
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue