mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
Add a layout debug module. This outputs a trace of the layout process to a JSON
file which can be viewed in an external tool. It provides a timelapse view of how the flow tree and fragments changed during the layout process, which makes it easier to debug layout bugs.
This commit is contained in:
parent
940c013176
commit
acedb16670
16 changed files with 261 additions and 16 deletions
|
@ -66,6 +66,7 @@ pub extern "C" fn cef_run_message_loop() {
|
||||||
bubble_inline_sizes_separately: false,
|
bubble_inline_sizes_separately: false,
|
||||||
show_debug_borders: false,
|
show_debug_borders: false,
|
||||||
enable_text_antialiasing: true,
|
enable_text_antialiasing: true,
|
||||||
|
trace_layout: false,
|
||||||
};
|
};
|
||||||
native::start(0, 0 as *const *const u8, proc() {
|
native::start(0, 0 as *const *const u8, proc() {
|
||||||
servo::run(opts);
|
servo::run(opts);
|
||||||
|
|
|
@ -21,6 +21,7 @@ extern crate native;
|
||||||
extern crate rustrt;
|
extern crate rustrt;
|
||||||
extern crate stb_image;
|
extern crate stb_image;
|
||||||
extern crate png;
|
extern crate png;
|
||||||
|
extern crate serialize;
|
||||||
#[phase(plugin)]
|
#[phase(plugin)]
|
||||||
extern crate servo_macros = "macros";
|
extern crate servo_macros = "macros";
|
||||||
extern crate servo_net = "net";
|
extern crate servo_net = "net";
|
||||||
|
|
|
@ -511,6 +511,7 @@ pub struct GlyphStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
int_range_index! {
|
int_range_index! {
|
||||||
|
#[deriving(Encodable)]
|
||||||
#[doc = "An index that refers to a character in a text run. This could \
|
#[doc = "An index that refers to a character in a text run. This could \
|
||||||
point to the middle of a glyph."]
|
point to the middle of a glyph."]
|
||||||
struct CharIndex(int)
|
struct CharIndex(int)
|
||||||
|
|
|
@ -21,6 +21,7 @@ use flow::{BaseFlow, BlockFlowClass, FlowClass, Flow, ImmutableFlowUtils};
|
||||||
use flow::{MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal, mut_base};
|
use flow::{MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal, mut_base};
|
||||||
use flow;
|
use flow;
|
||||||
use fragment::{Fragment, ImageFragment, ScannedTextFragment};
|
use fragment::{Fragment, ImageFragment, ScannedTextFragment};
|
||||||
|
use layout_debug;
|
||||||
use model::{Auto, IntrinsicISizes, MarginCollapseInfo, MarginsCollapse};
|
use model::{Auto, IntrinsicISizes, MarginCollapseInfo, MarginsCollapse};
|
||||||
use model::{MarginsCollapseThrough, MaybeAuto, NoCollapsibleMargins, Specified, specified};
|
use model::{MarginsCollapseThrough, MaybeAuto, NoCollapsibleMargins, Specified, specified};
|
||||||
use model::{specified_or_none};
|
use model::{specified_or_none};
|
||||||
|
@ -48,6 +49,7 @@ use style::computed_values::{display, float, overflow};
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
|
|
||||||
/// Information specific to floated blocks.
|
/// Information specific to floated blocks.
|
||||||
|
#[deriving(Encodable)]
|
||||||
pub struct FloatedBlockInfo {
|
pub struct FloatedBlockInfo {
|
||||||
pub containing_inline_size: Au,
|
pub containing_inline_size: Au,
|
||||||
|
|
||||||
|
@ -492,6 +494,7 @@ fn propagate_layer_flag_from_child(layers_needed_for_descendants: &mut bool, kid
|
||||||
}
|
}
|
||||||
|
|
||||||
// A block formatting context.
|
// A block formatting context.
|
||||||
|
#[deriving(Encodable)]
|
||||||
pub struct BlockFlow {
|
pub struct BlockFlow {
|
||||||
/// Data common to all flows.
|
/// Data common to all flows.
|
||||||
pub base: BaseFlow,
|
pub base: BaseFlow,
|
||||||
|
@ -808,6 +811,8 @@ impl BlockFlow {
|
||||||
pub fn assign_block_size_block_base<'a>(&mut self,
|
pub fn assign_block_size_block_base<'a>(&mut self,
|
||||||
layout_context: &'a LayoutContext<'a>,
|
layout_context: &'a LayoutContext<'a>,
|
||||||
margins_may_collapse: MarginsMayCollapseFlag) {
|
margins_may_collapse: MarginsMayCollapseFlag) {
|
||||||
|
let _scope = layout_debug::Scope::new(format!("assign_block_size_block_base {:s}", self.base.debug_id()));
|
||||||
|
|
||||||
// Our current border-box position.
|
// Our current border-box position.
|
||||||
let mut cur_b = Au(0);
|
let mut cur_b = Au(0);
|
||||||
|
|
||||||
|
@ -1054,6 +1059,8 @@ impl BlockFlow {
|
||||||
///
|
///
|
||||||
/// It does not calculate the block-size of the flow itself.
|
/// It does not calculate the block-size of the flow itself.
|
||||||
pub fn assign_block_size_float<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
|
pub fn assign_block_size_float<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
|
||||||
|
let _scope = layout_debug::Scope::new(format!("assign_block_size_float {:s}", self.base.debug_id()));
|
||||||
|
|
||||||
let mut floats = Floats::new(self.fragment.style.writing_mode);
|
let mut floats = Floats::new(self.fragment.style.writing_mode);
|
||||||
for kid in self.base.child_iter() {
|
for kid in self.base.child_iter() {
|
||||||
flow::mut_base(kid).floats = floats.clone();
|
flow::mut_base(kid).floats = floats.clone();
|
||||||
|
@ -1432,6 +1439,10 @@ impl Flow for BlockFlow {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_immutable_block<'a>(&'a self) -> &'a BlockFlow {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the direction that this flow clears floats in, if any.
|
/// Returns the direction that this flow clears floats in, if any.
|
||||||
fn float_clearance(&self) -> clear::T {
|
fn float_clearance(&self) -> clear::T {
|
||||||
self.fragment.style().get_box().clear
|
self.fragment.style().get_box().clear
|
||||||
|
@ -1446,6 +1457,8 @@ impl Flow for BlockFlow {
|
||||||
///
|
///
|
||||||
/// TODO(pcwalton): Inline blocks.
|
/// TODO(pcwalton): Inline blocks.
|
||||||
fn bubble_inline_sizes(&mut self, _: &LayoutContext) {
|
fn bubble_inline_sizes(&mut self, _: &LayoutContext) {
|
||||||
|
let _scope = layout_debug::Scope::new(format!("block::bubble_inline_sizes {:s}", self.base.debug_id()));
|
||||||
|
|
||||||
let mut flags = self.base.flags;
|
let mut flags = self.base.flags;
|
||||||
flags.set_has_left_floated_descendants(false);
|
flags.set_has_left_floated_descendants(false);
|
||||||
flags.set_has_right_floated_descendants(false);
|
flags.set_has_right_floated_descendants(false);
|
||||||
|
@ -1490,6 +1503,8 @@ impl Flow for BlockFlow {
|
||||||
/// Dual fragments consume some inline-size first, and the remainder is assigned to all child (block)
|
/// Dual fragments consume some inline-size first, and the remainder is assigned to all child (block)
|
||||||
/// contexts.
|
/// contexts.
|
||||||
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
|
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
|
||||||
|
let _scope = layout_debug::Scope::new(format!("block::assign_inline_sizes {:s}", self.base.debug_id()));
|
||||||
|
|
||||||
debug!("assign_inline_sizes({}): assigning inline_size for flow",
|
debug!("assign_inline_sizes({}): assigning inline_size for flow",
|
||||||
if self.is_float() {
|
if self.is_float() {
|
||||||
"float"
|
"float"
|
||||||
|
|
|
@ -11,7 +11,7 @@ use style::computed_values::float;
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
|
|
||||||
/// The kind of float: left or right.
|
/// The kind of float: left or right.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone, Encodable)]
|
||||||
pub enum FloatKind {
|
pub enum FloatKind {
|
||||||
FloatLeft,
|
FloatLeft,
|
||||||
FloatRight
|
FloatRight
|
||||||
|
|
|
@ -49,6 +49,7 @@ use collections::dlist::DList;
|
||||||
use geom::Point2D;
|
use geom::Point2D;
|
||||||
use gfx::display_list::DisplayList;
|
use gfx::display_list::DisplayList;
|
||||||
use gfx::render_task::RenderLayer;
|
use gfx::render_task::RenderLayer;
|
||||||
|
use serialize::{Encoder, Encodable};
|
||||||
use servo_msg::compositor_msg::LayerId;
|
use servo_msg::compositor_msg::LayerId;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::logical_geometry::WritingMode;
|
use servo_util::logical_geometry::WritingMode;
|
||||||
|
@ -74,6 +75,12 @@ pub trait Flow: fmt::Show + ToString + Share {
|
||||||
/// Returns the class of flow that this is.
|
/// Returns the class of flow that this is.
|
||||||
fn class(&self) -> FlowClass;
|
fn class(&self) -> FlowClass;
|
||||||
|
|
||||||
|
/// If this is a block flow, returns the underlying object, borrowed immutably. Fails
|
||||||
|
/// otherwise.
|
||||||
|
fn as_immutable_block<'a>(&'a self) -> &'a BlockFlow {
|
||||||
|
fail!("called as_immutable_block() on a non-block flow")
|
||||||
|
}
|
||||||
|
|
||||||
/// If this is a block flow, returns the underlying object. Fails otherwise.
|
/// If this is a block flow, returns the underlying object. Fails otherwise.
|
||||||
fn as_block<'a>(&'a mut self) -> &'a mut BlockFlow {
|
fn as_block<'a>(&'a mut self) -> &'a mut BlockFlow {
|
||||||
debug!("called as_block() on a flow of type {}", self.class());
|
debug!("called as_block() on a flow of type {}", self.class());
|
||||||
|
@ -270,6 +277,21 @@ pub trait Flow: fmt::Show + ToString + Share {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, E, S: Encoder<E>> Encodable<S, E> for &'a Flow {
|
||||||
|
fn encode(&self, e: &mut S) -> Result<(), E> {
|
||||||
|
e.emit_struct("flow", 0, |e| {
|
||||||
|
try!(e.emit_struct_field("class", 0, |e| self.class().encode(e)))
|
||||||
|
e.emit_struct_field("data", 1, |e| {
|
||||||
|
match self.class() {
|
||||||
|
BlockFlowClass => self.as_immutable_block().encode(e),
|
||||||
|
InlineFlowClass => self.as_immutable_inline().encode(e),
|
||||||
|
_ => { Ok(()) } // TODO: Support tables
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Base access
|
// Base access
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -381,7 +403,7 @@ pub trait MutableOwnedFlowUtils {
|
||||||
fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants);
|
fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq, Show)]
|
#[deriving(Encodable, PartialEq, Show)]
|
||||||
pub enum FlowClass {
|
pub enum FlowClass {
|
||||||
BlockFlowClass,
|
BlockFlowClass,
|
||||||
InlineFlowClass,
|
InlineFlowClass,
|
||||||
|
@ -428,7 +450,7 @@ pub trait PostorderFlowTraversal {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flags used in flows, tightly packed to save space.
|
/// Flags used in flows, tightly packed to save space.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone, Encodable)]
|
||||||
pub struct FlowFlags(pub u8);
|
pub struct FlowFlags(pub u8);
|
||||||
|
|
||||||
/// The bitmask of flags that represent the `has_left_floated_descendants` and
|
/// The bitmask of flags that represent the `has_left_floated_descendants` and
|
||||||
|
@ -595,6 +617,7 @@ pub type DescendantOffsetIter<'a> = Zip<DescendantIter<'a>, MutItems<'a, Au>>;
|
||||||
|
|
||||||
/// Information needed to compute absolute (i.e. viewport-relative) flow positions (not to be
|
/// Information needed to compute absolute (i.e. viewport-relative) flow positions (not to be
|
||||||
/// confused with absolutely-positioned flows).
|
/// confused with absolutely-positioned flows).
|
||||||
|
#[deriving(Encodable)]
|
||||||
pub struct AbsolutePositionInfo {
|
pub struct AbsolutePositionInfo {
|
||||||
/// The size of the containing block for relatively-positioned descendants.
|
/// The size of the containing block for relatively-positioned descendants.
|
||||||
pub relative_containing_block_size: LogicalSize<Au>,
|
pub relative_containing_block_size: LogicalSize<Au>,
|
||||||
|
@ -697,6 +720,26 @@ pub struct BaseFlow {
|
||||||
pub writing_mode: WritingMode,
|
pub writing_mode: WritingMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E, S: Encoder<E>> Encodable<S, E> for BaseFlow {
|
||||||
|
fn encode(&self, e: &mut S) -> Result<(), E> {
|
||||||
|
e.emit_struct("base", 0, |e| {
|
||||||
|
try!(e.emit_struct_field("id", 0, |e| self.debug_id().encode(e)))
|
||||||
|
try!(e.emit_struct_field("abs_position", 1, |e| self.abs_position.encode(e)))
|
||||||
|
try!(e.emit_struct_field("intrinsic_inline_sizes", 2, |e| self.intrinsic_inline_sizes.encode(e)))
|
||||||
|
try!(e.emit_struct_field("position", 3, |e| self.position.encode(e)))
|
||||||
|
e.emit_struct_field("children", 4, |e| {
|
||||||
|
e.emit_seq(self.children.len(), |e| {
|
||||||
|
for (i, c) in self.children.iter().enumerate() {
|
||||||
|
try!(e.emit_seq_elt(i, |e| c.encode(e)))
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[unsafe_destructor]
|
||||||
impl Drop for BaseFlow {
|
impl Drop for BaseFlow {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
@ -748,6 +791,10 @@ impl BaseFlow {
|
||||||
pub unsafe fn ref_count<'a>(&'a self) -> &'a AtomicUint {
|
pub unsafe fn ref_count<'a>(&'a self) -> &'a AtomicUint {
|
||||||
&self.ref_count
|
&self.ref_count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn debug_id(&self) -> String {
|
||||||
|
format!("{:p}", self as *const _)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ImmutableFlowUtils for &'a Flow {
|
impl<'a> ImmutableFlowUtils for &'a Flow {
|
||||||
|
|
|
@ -13,6 +13,7 @@ use floats::{ClearBoth, ClearLeft, ClearRight, ClearType};
|
||||||
use flow::Flow;
|
use flow::Flow;
|
||||||
use flow;
|
use flow;
|
||||||
use inline::{InlineFragmentContext, InlineMetrics};
|
use inline::{InlineFragmentContext, InlineMetrics};
|
||||||
|
use layout_debug;
|
||||||
use model::{Auto, IntrinsicISizes, MaybeAuto, Specified, specified};
|
use model::{Auto, IntrinsicISizes, MaybeAuto, Specified, specified};
|
||||||
use model;
|
use model;
|
||||||
use text;
|
use text;
|
||||||
|
@ -33,6 +34,7 @@ use gfx::display_list::{Upright, SidewaysLeft, SidewaysRight};
|
||||||
use gfx::font::FontStyle;
|
use gfx::font::FontStyle;
|
||||||
use gfx::text::glyph::CharIndex;
|
use gfx::text::glyph::CharIndex;
|
||||||
use gfx::text::text_run::TextRun;
|
use gfx::text::text_run::TextRun;
|
||||||
|
use serialize::{Encodable, Encoder};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId};
|
use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId};
|
||||||
use servo_net::image::holder::ImageHolder;
|
use servo_net::image::holder::ImageHolder;
|
||||||
use servo_net::local_image_cache::LocalImageCache;
|
use servo_net::local_image_cache::LocalImageCache;
|
||||||
|
@ -104,6 +106,20 @@ pub struct Fragment {
|
||||||
/// Holds the style context information for fragments
|
/// Holds the style context information for fragments
|
||||||
/// that are part of an inline formatting context.
|
/// that are part of an inline formatting context.
|
||||||
pub inline_context: Option<InlineFragmentContext>,
|
pub inline_context: Option<InlineFragmentContext>,
|
||||||
|
|
||||||
|
/// A debug ID that is consistent for the life of
|
||||||
|
/// this fragment (via transform etc).
|
||||||
|
pub debug_id: uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, S: Encoder<E>> Encodable<S, E> for Fragment {
|
||||||
|
fn encode(&self, e: &mut S) -> Result<(), E> {
|
||||||
|
e.emit_struct("fragment", 0, |e| {
|
||||||
|
try!(e.emit_struct_field("id", 0, |e| self.debug_id().encode(e)))
|
||||||
|
try!(e.emit_struct_field("border_box", 1, |e| self.border_box.encode(e)))
|
||||||
|
e.emit_struct_field("margin", 2, |e| self.margin.encode(e))
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Info specific to the kind of fragment. Keep this enum small.
|
/// Info specific to the kind of fragment. Keep this enum small.
|
||||||
|
@ -336,6 +352,7 @@ impl Fragment {
|
||||||
specific: constructor.build_specific_fragment_info_for_node(node),
|
specific: constructor.build_specific_fragment_info_for_node(node),
|
||||||
new_line_pos: vec!(),
|
new_line_pos: vec!(),
|
||||||
inline_context: None,
|
inline_context: None,
|
||||||
|
debug_id: layout_debug::generate_unique_debug_id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,6 +369,7 @@ impl Fragment {
|
||||||
specific: specific,
|
specific: specific,
|
||||||
new_line_pos: vec!(),
|
new_line_pos: vec!(),
|
||||||
inline_context: None,
|
inline_context: None,
|
||||||
|
debug_id: layout_debug::generate_unique_debug_id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,6 +395,7 @@ impl Fragment {
|
||||||
specific: specific,
|
specific: specific,
|
||||||
new_line_pos: vec!(),
|
new_line_pos: vec!(),
|
||||||
inline_context: None,
|
inline_context: None,
|
||||||
|
debug_id: layout_debug::generate_unique_debug_id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,13 +414,14 @@ impl Fragment {
|
||||||
specific: specific,
|
specific: specific,
|
||||||
new_line_pos: vec!(),
|
new_line_pos: vec!(),
|
||||||
inline_context: None,
|
inline_context: None,
|
||||||
|
debug_id: layout_debug::generate_unique_debug_id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a debug ID of this fragment. This ID should not be considered stable across multiple
|
/// Returns a debug ID of this fragment. This ID should not be considered stable across multiple
|
||||||
/// layouts or fragment manipulations.
|
/// layouts or fragment manipulations.
|
||||||
pub fn debug_id(&self) -> uint {
|
pub fn debug_id(&self) -> uint {
|
||||||
self as *const Fragment as uint
|
self.debug_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transforms this fragment into another fragment of the given type, with the given size, preserving all
|
/// Transforms this fragment into another fragment of the given type, with the given size, preserving all
|
||||||
|
@ -417,6 +437,7 @@ impl Fragment {
|
||||||
specific: specific,
|
specific: specific,
|
||||||
new_line_pos: self.new_line_pos.clone(),
|
new_line_pos: self.new_line_pos.clone(),
|
||||||
inline_context: self.inline_context.clone(),
|
inline_context: self.inline_context.clone(),
|
||||||
|
debug_id: self.debug_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use floats::{FloatLeft, Floats, PlacementInfo};
|
||||||
use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass};
|
use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass};
|
||||||
use flow;
|
use flow;
|
||||||
use fragment::{Fragment, ScannedTextFragment, ScannedTextFragmentInfo, SplitInfo};
|
use fragment::{Fragment, ScannedTextFragment, ScannedTextFragmentInfo, SplitInfo};
|
||||||
|
use layout_debug;
|
||||||
use model::IntrinsicISizes;
|
use model::IntrinsicISizes;
|
||||||
use text;
|
use text;
|
||||||
use wrapper::ThreadSafeLayoutNode;
|
use wrapper::ThreadSafeLayoutNode;
|
||||||
|
@ -58,6 +59,7 @@ use sync::Arc;
|
||||||
/// with a float or a horizontal wall of the containing block. The block-start
|
/// with a float or a horizontal wall of the containing block. The block-start
|
||||||
/// inline-start corner of the green zone is the same as that of the line, but
|
/// inline-start corner of the green zone is the same as that of the line, but
|
||||||
/// the green zone can be taller and wider than the line itself.
|
/// the green zone can be taller and wider than the line itself.
|
||||||
|
#[deriving(Encodable)]
|
||||||
pub struct Line {
|
pub struct Line {
|
||||||
/// A range of line indices that describe line breaks.
|
/// A range of line indices that describe line breaks.
|
||||||
///
|
///
|
||||||
|
@ -140,6 +142,7 @@ pub struct Line {
|
||||||
}
|
}
|
||||||
|
|
||||||
int_range_index! {
|
int_range_index! {
|
||||||
|
#[deriving(Encodable)]
|
||||||
#[doc = "The index of a fragment in a flattened vector of DOM elements."]
|
#[doc = "The index of a fragment in a flattened vector of DOM elements."]
|
||||||
struct FragmentIndex(int)
|
struct FragmentIndex(int)
|
||||||
}
|
}
|
||||||
|
@ -147,7 +150,7 @@ int_range_index! {
|
||||||
/// A line index consists of two indices: a fragment index that refers to the
|
/// A line index consists of two indices: a fragment index that refers to the
|
||||||
/// index of a DOM fragment within a flattened inline element; and a glyph index
|
/// index of a DOM fragment within a flattened inline element; and a glyph index
|
||||||
/// where the 0th glyph refers to the first glyph of that fragment.
|
/// where the 0th glyph refers to the first glyph of that fragment.
|
||||||
#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Zero)]
|
#[deriving(Clone, Encodable, PartialEq, PartialOrd, Eq, Ord, Zero)]
|
||||||
pub struct LineIndices {
|
pub struct LineIndices {
|
||||||
/// The index of a fragment into the flattened vector of DOM elements.
|
/// The index of a fragment into the flattened vector of DOM elements.
|
||||||
///
|
///
|
||||||
|
@ -625,6 +628,7 @@ impl LineBreaker {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a list of inline fragments, including element ranges.
|
/// Represents a list of inline fragments, including element ranges.
|
||||||
|
#[deriving(Encodable)]
|
||||||
pub struct InlineFragments {
|
pub struct InlineFragments {
|
||||||
/// The fragments themselves.
|
/// The fragments themselves.
|
||||||
pub fragments: Vec<Fragment>,
|
pub fragments: Vec<Fragment>,
|
||||||
|
@ -709,6 +713,7 @@ impl InlineFragments {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flows for inline layout.
|
/// Flows for inline layout.
|
||||||
|
#[deriving(Encodable)]
|
||||||
pub struct InlineFlow {
|
pub struct InlineFlow {
|
||||||
/// Data common to all flows.
|
/// Data common to all flows.
|
||||||
pub base: BaseFlow,
|
pub base: BaseFlow,
|
||||||
|
@ -902,6 +907,8 @@ impl Flow for InlineFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bubble_inline_sizes(&mut self, _: &LayoutContext) {
|
fn bubble_inline_sizes(&mut self, _: &LayoutContext) {
|
||||||
|
let _scope = layout_debug::Scope::new(format!("inline::bubble_inline_sizes {:s}", self.base.debug_id()));
|
||||||
|
|
||||||
let writing_mode = self.base.writing_mode;
|
let writing_mode = self.base.writing_mode;
|
||||||
for kid in self.base.child_iter() {
|
for kid in self.base.child_iter() {
|
||||||
flow::mut_base(kid).floats = Floats::new(writing_mode);
|
flow::mut_base(kid).floats = Floats::new(writing_mode);
|
||||||
|
@ -927,6 +934,8 @@ impl Flow for InlineFlow {
|
||||||
/// Recursively (top-down) determines the actual inline-size of child contexts and fragments. When called
|
/// Recursively (top-down) determines the actual inline-size of child contexts and fragments. When called
|
||||||
/// on this context, the context has had its inline-size set by the parent context.
|
/// on this context, the context has had its inline-size set by the parent context.
|
||||||
fn assign_inline_sizes(&mut self, _: &LayoutContext) {
|
fn assign_inline_sizes(&mut self, _: &LayoutContext) {
|
||||||
|
let _scope = layout_debug::Scope::new(format!("inline::assign_inline_sizes {:s}", self.base.debug_id()));
|
||||||
|
|
||||||
// Initialize content fragment inline-sizes if they haven't been initialized already.
|
// Initialize content fragment inline-sizes if they haven't been initialized already.
|
||||||
//
|
//
|
||||||
// TODO: Combine this with `LineBreaker`'s walk in the fragment list, or put this into `Fragment`.
|
// TODO: Combine this with `LineBreaker`'s walk in the fragment list, or put this into `Fragment`.
|
||||||
|
@ -955,6 +964,7 @@ impl Flow for InlineFlow {
|
||||||
|
|
||||||
/// Calculate and set the block-size of this flow. See CSS 2.1 § 10.6.1.
|
/// Calculate and set the block-size of this flow. See CSS 2.1 § 10.6.1.
|
||||||
fn assign_block_size(&mut self, ctx: &LayoutContext) {
|
fn assign_block_size(&mut self, ctx: &LayoutContext) {
|
||||||
|
let _scope = layout_debug::Scope::new(format!("inline::assign_block_size {:s}", self.base.debug_id()));
|
||||||
debug!("assign_block_size_inline: assigning block_size for flow");
|
debug!("assign_block_size_inline: assigning block_size for flow");
|
||||||
|
|
||||||
// Divide the fragments into lines.
|
// Divide the fragments into lines.
|
||||||
|
|
|
@ -20,6 +20,7 @@ extern crate gfx;
|
||||||
extern crate layout_traits;
|
extern crate layout_traits;
|
||||||
extern crate script;
|
extern crate script;
|
||||||
extern crate script_traits;
|
extern crate script_traits;
|
||||||
|
extern crate serialize;
|
||||||
extern crate style;
|
extern crate style;
|
||||||
#[phase(plugin)]
|
#[phase(plugin)]
|
||||||
extern crate servo_macros = "macros";
|
extern crate servo_macros = "macros";
|
||||||
|
@ -42,6 +43,7 @@ pub mod flow;
|
||||||
pub mod flow_list;
|
pub mod flow_list;
|
||||||
pub mod flow_ref;
|
pub mod flow_ref;
|
||||||
pub mod fragment;
|
pub mod fragment;
|
||||||
|
pub mod layout_debug;
|
||||||
pub mod layout_task;
|
pub mod layout_task;
|
||||||
pub mod inline;
|
pub mod inline;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
|
112
src/components/layout/layout_debug.rs
Normal file
112
src/components/layout/layout_debug.rs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
//! Supports writing a trace file created during each layout scope
|
||||||
|
//! that can be viewed by an external tool to make layout debugging easier.
|
||||||
|
|
||||||
|
use flow_ref::FlowRef;
|
||||||
|
use serialize::json;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::io::File;
|
||||||
|
use std::sync::atomics::{AtomicUint, SeqCst, INIT_ATOMIC_UINT};
|
||||||
|
|
||||||
|
local_data_key!(state_key: RefCell<State>)
|
||||||
|
|
||||||
|
static mut DEBUG_ID_COUNTER: AtomicUint = INIT_ATOMIC_UINT;
|
||||||
|
|
||||||
|
pub struct Scope;
|
||||||
|
|
||||||
|
#[deriving(Encodable)]
|
||||||
|
struct ScopeData {
|
||||||
|
name: String,
|
||||||
|
pre: String,
|
||||||
|
post: String,
|
||||||
|
children: Vec<Box<ScopeData>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScopeData {
|
||||||
|
fn new(name: String, pre: String) -> ScopeData {
|
||||||
|
ScopeData {
|
||||||
|
name: name,
|
||||||
|
pre: pre,
|
||||||
|
post: String::new(),
|
||||||
|
children: vec!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
flow_root: FlowRef,
|
||||||
|
scope_stack: Vec<Box<ScopeData>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A layout debugging scope. The entire state of the flow tree
|
||||||
|
/// will be output at the beginning and end of this scope.
|
||||||
|
impl Scope {
|
||||||
|
pub fn new(name: String) -> Scope {
|
||||||
|
let maybe_refcell = state_key.get();
|
||||||
|
match maybe_refcell {
|
||||||
|
Some(refcell) => {
|
||||||
|
let mut state = refcell.borrow_mut();
|
||||||
|
let flow_trace = json::encode(&state.flow_root.get());
|
||||||
|
let data = box ScopeData::new(name, flow_trace);
|
||||||
|
state.scope_stack.push(data);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
Scope
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Scope {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let maybe_refcell = state_key.get();
|
||||||
|
match maybe_refcell {
|
||||||
|
Some(refcell) => {
|
||||||
|
let mut state = refcell.borrow_mut();
|
||||||
|
let mut current_scope = state.scope_stack.pop().unwrap();
|
||||||
|
current_scope.post = json::encode(&state.flow_root.get());
|
||||||
|
let previous_scope = state.scope_stack.mut_last().unwrap();
|
||||||
|
previous_scope.children.push(current_scope);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a unique ID. This is used for items such as Fragment
|
||||||
|
/// which are often reallocated but represent essentially the
|
||||||
|
/// same data.
|
||||||
|
pub fn generate_unique_debug_id() -> uint {
|
||||||
|
unsafe { DEBUG_ID_COUNTER.fetch_add(1, SeqCst) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Begin a layout debug trace. If this has not been called,
|
||||||
|
/// creating debug scopes has no effect.
|
||||||
|
pub fn begin_trace(flow_root: FlowRef) {
|
||||||
|
assert!(state_key.get().is_none());
|
||||||
|
|
||||||
|
let flow_trace = json::encode(&flow_root.get());
|
||||||
|
let state = State {
|
||||||
|
scope_stack: vec![box ScopeData::new("root".to_string(), flow_trace)],
|
||||||
|
flow_root: flow_root,
|
||||||
|
};
|
||||||
|
state_key.replace(Some(RefCell::new(state)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// End the debug layout trace. This will write the layout
|
||||||
|
/// trace to disk in the current directory. The output
|
||||||
|
/// file can then be viewed with an external tool.
|
||||||
|
pub fn end_trace() {
|
||||||
|
let task_state_cell = state_key.replace(None).unwrap();
|
||||||
|
let mut task_state = task_state_cell.borrow_mut();
|
||||||
|
assert!(task_state.scope_stack.len() == 1);
|
||||||
|
let mut root_scope = task_state.scope_stack.pop().unwrap();
|
||||||
|
root_scope.post = json::encode(&task_state.flow_root.get());
|
||||||
|
|
||||||
|
let result = json::encode(&root_scope);
|
||||||
|
let path = Path::new("layout_trace.json");
|
||||||
|
let mut file = File::create(&path).unwrap();
|
||||||
|
file.write_str(result.as_slice()).unwrap();
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ use flow::{PreorderFlowTraversal, PostorderFlowTraversal};
|
||||||
use flow;
|
use flow;
|
||||||
use flow_ref::FlowRef;
|
use flow_ref::FlowRef;
|
||||||
use incremental::RestyleDamage;
|
use incremental::RestyleDamage;
|
||||||
|
use layout_debug;
|
||||||
use parallel::UnsafeFlow;
|
use parallel::UnsafeFlow;
|
||||||
use parallel;
|
use parallel;
|
||||||
use util::{LayoutDataAccess, LayoutDataWrapper, OpaqueNodeMethods, ToGfxColor};
|
use util::{LayoutDataAccess, LayoutDataWrapper, OpaqueNodeMethods, ToGfxColor};
|
||||||
|
@ -530,6 +531,8 @@ impl LayoutTask {
|
||||||
fn solve_constraints<'a>(&mut self,
|
fn solve_constraints<'a>(&mut self,
|
||||||
layout_root: &mut Flow,
|
layout_root: &mut Flow,
|
||||||
layout_context: &'a LayoutContext<'a>) {
|
layout_context: &'a LayoutContext<'a>) {
|
||||||
|
let _scope = layout_debug::Scope::new("solve_constraints".to_string());
|
||||||
|
|
||||||
if layout_context.shared.opts.bubble_inline_sizes_separately {
|
if layout_context.shared.opts.bubble_inline_sizes_separately {
|
||||||
let mut traversal = BubbleISizesTraversal {
|
let mut traversal = BubbleISizesTraversal {
|
||||||
layout_context: layout_context,
|
layout_context: layout_context,
|
||||||
|
@ -667,6 +670,10 @@ impl LayoutTask {
|
||||||
// memory safety but is a useful debugging tool.)
|
// memory safety but is a useful debugging tool.)
|
||||||
self.verify_flow_tree(&mut layout_root);
|
self.verify_flow_tree(&mut layout_root);
|
||||||
|
|
||||||
|
if self.opts.trace_layout {
|
||||||
|
layout_debug::begin_trace(layout_root.clone());
|
||||||
|
}
|
||||||
|
|
||||||
// Propagate damage.
|
// Propagate damage.
|
||||||
profile(time::LayoutDamagePropagateCategory, self.time_profiler_chan.clone(), || {
|
profile(time::LayoutDamagePropagateCategory, self.time_profiler_chan.clone(), || {
|
||||||
layout_root.get_mut().traverse_preorder(&mut PropagateDamageTraversal {
|
layout_root.get_mut().traverse_preorder(&mut PropagateDamageTraversal {
|
||||||
|
@ -778,6 +785,10 @@ impl LayoutTask {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.opts.trace_layout {
|
||||||
|
layout_debug::end_trace();
|
||||||
|
}
|
||||||
|
|
||||||
// Tell script that we're done.
|
// Tell script that we're done.
|
||||||
//
|
//
|
||||||
// FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
|
// FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
|
||||||
|
|
|
@ -243,6 +243,7 @@ pub enum MarginCollapseState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Intrinsic inline-sizes, which consist of minimum and preferred.
|
/// Intrinsic inline-sizes, which consist of minimum and preferred.
|
||||||
|
#[deriving(Encodable)]
|
||||||
pub struct IntrinsicISizes {
|
pub struct IntrinsicISizes {
|
||||||
/// The *minimum inline-size* of the content.
|
/// The *minimum inline-size* of the content.
|
||||||
pub minimum_inline_size: Au,
|
pub minimum_inline_size: Au,
|
||||||
|
|
|
@ -7,6 +7,7 @@ use geom::point::Point2D;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
|
||||||
|
use serialize::{Encodable, Encoder};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::num::{NumCast, One, Zero};
|
use std::num::{NumCast, One, Zero};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -71,6 +72,12 @@ impl Default for Au {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E, S: Encoder<E>> Encodable<S, E> for Au {
|
||||||
|
fn encode(&self, e: &mut S) -> Result<(), E> {
|
||||||
|
e.emit_f64(to_frac_px(*self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Show for Au {
|
impl fmt::Show for Au {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}px", to_frac_px(*self))
|
write!(f, "{}px", to_frac_px(*self))
|
||||||
|
|
|
@ -9,8 +9,8 @@ use std::cmp::{min, max};
|
||||||
use std::fmt::{Show, Formatter, FormatError};
|
use std::fmt::{Show, Formatter, FormatError};
|
||||||
use std::num::Zero;
|
use std::num::Zero;
|
||||||
|
|
||||||
|
|
||||||
bitflags!(
|
bitflags!(
|
||||||
|
#[deriving(Encodable)]
|
||||||
flags WritingMode: u8 {
|
flags WritingMode: u8 {
|
||||||
static FlagRTL = 1 << 0,
|
static FlagRTL = 1 << 0,
|
||||||
static FlagVertical = 1 << 1,
|
static FlagVertical = 1 << 1,
|
||||||
|
@ -79,11 +79,11 @@ impl Show for WritingMode {
|
||||||
/// (in addition to taking it as a parameter to methods) and check it.
|
/// (in addition to taking it as a parameter to methods) and check it.
|
||||||
/// In non-debug builds, make this storage zero-size and the checks no-ops.
|
/// In non-debug builds, make this storage zero-size and the checks no-ops.
|
||||||
#[cfg(ndebug)]
|
#[cfg(ndebug)]
|
||||||
#[deriving(PartialEq, Eq, Clone)]
|
#[deriving(Encodable, PartialEq, Eq, Clone)]
|
||||||
struct DebugWritingMode;
|
struct DebugWritingMode;
|
||||||
|
|
||||||
#[cfg(not(ndebug))]
|
#[cfg(not(ndebug))]
|
||||||
#[deriving(PartialEq, Eq, Clone)]
|
#[deriving(Encodable, PartialEq, Eq, Clone)]
|
||||||
struct DebugWritingMode {
|
struct DebugWritingMode {
|
||||||
mode: WritingMode
|
mode: WritingMode
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ impl Show for DebugWritingMode {
|
||||||
|
|
||||||
|
|
||||||
/// A 2D size in flow-relative dimensions
|
/// A 2D size in flow-relative dimensions
|
||||||
#[deriving(PartialEq, Eq, Clone)]
|
#[deriving(Encodable, PartialEq, Eq, Clone)]
|
||||||
pub struct LogicalSize<T> {
|
pub struct LogicalSize<T> {
|
||||||
pub inline: T, // inline-size, a.k.a. logical width, a.k.a. measure
|
pub inline: T, // inline-size, a.k.a. logical width, a.k.a. measure
|
||||||
pub block: T, // block-size, a.k.a. logical height, a.k.a. extent
|
pub block: T, // block-size, a.k.a. logical height, a.k.a. extent
|
||||||
|
@ -271,7 +271,7 @@ impl<T: Sub<T, T>> Sub<LogicalSize<T>, LogicalSize<T>> for LogicalSize<T> {
|
||||||
|
|
||||||
|
|
||||||
/// A 2D point in flow-relative dimensions
|
/// A 2D point in flow-relative dimensions
|
||||||
#[deriving(PartialEq, Eq, Clone)]
|
#[deriving(PartialEq, Encodable, Eq, Clone)]
|
||||||
pub struct LogicalPoint<T> {
|
pub struct LogicalPoint<T> {
|
||||||
pub i: T, /// inline-axis coordinate
|
pub i: T, /// inline-axis coordinate
|
||||||
pub b: T, /// block-axis coordinate
|
pub b: T, /// block-axis coordinate
|
||||||
|
@ -444,7 +444,7 @@ impl<T: Sub<T,T>> Sub<LogicalSize<T>, LogicalPoint<T>> for LogicalPoint<T> {
|
||||||
/// Represents the four sides of the margins, borders, or padding of a CSS box,
|
/// Represents the four sides of the margins, borders, or padding of a CSS box,
|
||||||
/// or a combination of those.
|
/// or a combination of those.
|
||||||
/// A positive "margin" can be added to a rectangle to obtain a bigger rectangle.
|
/// A positive "margin" can be added to a rectangle to obtain a bigger rectangle.
|
||||||
#[deriving(PartialEq, Eq, Clone)]
|
#[deriving(Encodable, PartialEq, Eq, Clone)]
|
||||||
pub struct LogicalMargin<T> {
|
pub struct LogicalMargin<T> {
|
||||||
pub block_start: T,
|
pub block_start: T,
|
||||||
pub inline_end: T,
|
pub inline_end: T,
|
||||||
|
@ -726,7 +726,7 @@ impl<T: Sub<T, T>> Sub<LogicalMargin<T>, LogicalMargin<T>> for LogicalMargin<T>
|
||||||
|
|
||||||
|
|
||||||
/// A rectangle in flow-relative dimensions
|
/// A rectangle in flow-relative dimensions
|
||||||
#[deriving(PartialEq, Eq, Clone)]
|
#[deriving(Encodable, PartialEq, Eq, Clone)]
|
||||||
pub struct LogicalRect<T> {
|
pub struct LogicalRect<T> {
|
||||||
pub start: LogicalPoint<T>,
|
pub start: LogicalPoint<T>,
|
||||||
pub size: LogicalSize<T>,
|
pub size: LogicalSize<T>,
|
||||||
|
|
|
@ -78,6 +78,11 @@ pub struct Opts {
|
||||||
/// where pixel perfect results are required when using fonts such as the Ahem
|
/// where pixel perfect results are required when using fonts such as the Ahem
|
||||||
/// font for layout tests.
|
/// font for layout tests.
|
||||||
pub enable_text_antialiasing: bool,
|
pub enable_text_antialiasing: bool,
|
||||||
|
|
||||||
|
/// True if each step of layout is traced to an external JSON file
|
||||||
|
/// for debugging purposes. Settings this implies sequential layout
|
||||||
|
/// and render.
|
||||||
|
pub trace_layout: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_usage(app: &str, opts: &[getopts::OptGroup]) {
|
fn print_usage(app: &str, opts: &[getopts::OptGroup]) {
|
||||||
|
@ -111,6 +116,7 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
|
||||||
getopts::optflag("b", "bubble-widths", "Bubble intrinsic widths separately like other engines"),
|
getopts::optflag("b", "bubble-widths", "Bubble intrinsic widths separately like other engines"),
|
||||||
getopts::optflag("", "show-debug-borders", "Show debugging borders on layers and tiles."),
|
getopts::optflag("", "show-debug-borders", "Show debugging borders on layers and tiles."),
|
||||||
getopts::optflag("", "disable-text-aa", "Disable antialiasing for text rendering."),
|
getopts::optflag("", "disable-text-aa", "Disable antialiasing for text rendering."),
|
||||||
|
getopts::optflag("", "trace-layout", "Write layout trace to external file for debugging."),
|
||||||
getopts::optflag("h", "help", "Print this message")
|
getopts::optflag("h", "help", "Print this message")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -163,7 +169,7 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
|
||||||
ScaleFactor(from_str(dppx_str.as_slice()).unwrap())
|
ScaleFactor(from_str(dppx_str.as_slice()).unwrap())
|
||||||
);
|
);
|
||||||
|
|
||||||
let n_render_threads: uint = match opt_match.opt_str("t") {
|
let mut n_render_threads: uint = match opt_match.opt_str("t") {
|
||||||
Some(n_render_threads_str) => from_str(n_render_threads_str.as_slice()).unwrap(),
|
Some(n_render_threads_str) => from_str(n_render_threads_str.as_slice()).unwrap(),
|
||||||
None => 1, // FIXME: Number of cores.
|
None => 1, // FIXME: Number of cores.
|
||||||
};
|
};
|
||||||
|
@ -178,11 +184,20 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
|
||||||
|
|
||||||
let cpu_painting = opt_match.opt_present("c");
|
let cpu_painting = opt_match.opt_present("c");
|
||||||
|
|
||||||
let layout_threads: uint = match opt_match.opt_str("y") {
|
let mut layout_threads: uint = match opt_match.opt_str("y") {
|
||||||
Some(layout_threads_str) => from_str(layout_threads_str.as_slice()).unwrap(),
|
Some(layout_threads_str) => from_str(layout_threads_str.as_slice()).unwrap(),
|
||||||
None => cmp::max(rt::default_sched_threads() * 3 / 4, 1),
|
None => cmp::max(rt::default_sched_threads() * 3 / 4, 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut bubble_inline_sizes_separately = opt_match.opt_present("b");
|
||||||
|
|
||||||
|
let trace_layout = opt_match.opt_present("trace-layout");
|
||||||
|
if trace_layout {
|
||||||
|
n_render_threads = 1;
|
||||||
|
layout_threads = 1;
|
||||||
|
bubble_inline_sizes_separately = true;
|
||||||
|
}
|
||||||
|
|
||||||
Some(Opts {
|
Some(Opts {
|
||||||
urls: urls,
|
urls: urls,
|
||||||
render_backend: render_backend,
|
render_backend: render_backend,
|
||||||
|
@ -198,9 +213,10 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
|
||||||
output_file: opt_match.opt_str("o"),
|
output_file: opt_match.opt_str("o"),
|
||||||
headless: opt_match.opt_present("z"),
|
headless: opt_match.opt_present("z"),
|
||||||
hard_fail: opt_match.opt_present("f"),
|
hard_fail: opt_match.opt_present("f"),
|
||||||
bubble_inline_sizes_separately: opt_match.opt_present("b"),
|
bubble_inline_sizes_separately: bubble_inline_sizes_separately,
|
||||||
show_debug_borders: opt_match.opt_present("show-debug-borders"),
|
show_debug_borders: opt_match.opt_present("show-debug-borders"),
|
||||||
enable_text_antialiasing: !opt_match.opt_present("disable-text-aa"),
|
enable_text_antialiasing: !opt_match.opt_present("disable-text-aa"),
|
||||||
|
trace_layout: trace_layout,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@ pub enum RangeRelation<I> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A range of indices
|
/// A range of indices
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone, Encodable)]
|
||||||
pub struct Range<I> {
|
pub struct Range<I> {
|
||||||
begin: I,
|
begin: I,
|
||||||
length: I,
|
length: I,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue