servo: Merge #2869 - Convert layout code to use logical directions (rebase) (from SimonSapin:writing-modes-rebase)

Source-Repo: https://github.com/servo/servo
Source-Revision: 45379a6a6191f65cb227ce8e80c1ad73f16ebcf8
This commit is contained in:
Simon Sapin 2014-07-18 13:27:23 -07:00
Родитель 56b9ec01ff
Коммит 2453870c2f
27 изменённых файлов: 2674 добавлений и 2407 удалений

Просмотреть файл

@ -56,13 +56,14 @@ pub extern "C" fn cef_run_message_loop() {
device_pixels_per_px: None,
time_profiler_period: None,
memory_profiler_period: None,
enable_experimental: false,
layout_threads: 1,
//layout_threads: cmp::max(rt::default_sched_threads() * 3 / 4, 1),
exit_after_load: false,
output_file: None,
headless: false,
hard_fail: false,
bubble_widths_separately: false,
bubble_inline_sizes_separately: false,
};
native::start(0, 0 as **u8, proc() {
servo::run(opts);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -294,7 +294,7 @@ impl<'a> FlowConstructor<'a> {
let mut inline_flow = box InlineFlow::from_fragments((*node).clone(), fragments);
let (ascent, descent) = inline_flow.compute_minimum_ascent_and_descent(self.font_context(), &**node.style());
inline_flow.minimum_height_above_baseline = ascent;
inline_flow.minimum_block_size_above_baseline = ascent;
inline_flow.minimum_depth_below_baseline = descent;
let mut inline_flow = inline_flow as Box<Flow>;
TextRunScanner::new().scan_for_runs(self.font_context(), inline_flow);
@ -1037,10 +1037,10 @@ pub trait FlowConstructionUtils {
fn add_new_child(&mut self, new_child: FlowRef);
/// Finishes a flow. Once a flow is finished, no more child flows or boxes may be added to it.
/// This will normally run the bubble-widths (minimum and preferred -- i.e. intrinsic -- width)
/// calculation, unless the global `bubble_widths_separately` flag is on.
/// This will normally run the bubble-inline-sizes (minimum and preferred -- i.e. intrinsic -- inline-size)
/// calculation, unless the global `bubble_inline-sizes_separately` flag is on.
///
/// All flows must be finished at some point, or they will not have their intrinsic widths
/// All flows must be finished at some point, or they will not have their intrinsic inline-sizes
/// properly computed. (This is not, however, a memory safety problem.)
fn finish(&mut self, context: &mut LayoutContext);
}
@ -1062,16 +1062,16 @@ impl FlowConstructionUtils for FlowRef {
}
/// Finishes a flow. Once a flow is finished, no more child flows or fragments may be added to
/// it. This will normally run the bubble-widths (minimum and preferred -- i.e. intrinsic --
/// width) calculation, unless the global `bubble_widths_separately` flag is on.
/// it. This will normally run the bubble-inline-sizes (minimum and preferred -- i.e. intrinsic --
/// inline-size) calculation, unless the global `bubble_inline-sizes_separately` flag is on.
///
/// All flows must be finished at some point, or they will not have their intrinsic widths
/// All flows must be finished at some point, or they will not have their intrinsic inline-sizes
/// properly computed. (This is not, however, a memory safety problem.)
///
/// This must not be public because only the layout constructor can do this.
fn finish(&mut self, context: &mut LayoutContext) {
if !context.opts.bubble_widths_separately {
self.get_mut().bubble_widths(context)
if !context.opts.bubble_inline_sizes_separately {
self.get_mut().bubble_inline_sizes(context)
}
}
}

Просмотреть файл

@ -6,8 +6,7 @@
use css::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache};
use geom::rect::Rect;
use geom::size::Size2D;
use geom::{Rect, Size2D};
use gfx::display_list::OpaqueNode;
use gfx::font_context::FontContext;
use gfx::font_cache_task::FontCacheTask;

Просмотреть файл

@ -2,10 +2,9 @@
* 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 geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use servo_util::geometry::{Au, max, min};
use servo_util::logical_geometry::WritingMode;
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
use std::i32;
use std::fmt;
use style::computed_values::float;
@ -39,7 +38,7 @@ pub enum ClearType {
#[deriving(Clone)]
struct Float {
/// The boundaries of this float.
bounds: Rect<Au>,
bounds: LogicalRect<Au>,
/// The kind of float: left or right.
kind: FloatKind,
}
@ -58,22 +57,22 @@ impl fmt::Show for Float {
struct FloatList {
/// Information about each of the floats here.
floats: Vec<Float>,
/// Cached copy of the maximum top offset of the float.
max_top: Au,
/// Cached copy of the maximum block-start offset of the float.
max_block_start: Au,
}
impl FloatList {
fn new() -> FloatList {
FloatList {
floats: vec!(),
max_top: Au(0),
max_block_start: Au(0),
}
}
}
impl fmt::Show for FloatList {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "max_top={} floats={:?}", self.max_top, self.floats)
write!(f, "max_block_start={} floats={:?}", self.max_block_start, self.floats)
}
}
@ -119,23 +118,23 @@ impl FloatListRef {
/// All the information necessary to place a float.
pub struct PlacementInfo {
/// The dimensions of the float.
pub size: Size2D<Au>,
/// The minimum top of the float, as determined by earlier elements.
pub size: LogicalSize<Au>,
/// The minimum block-start of the float, as determined by earlier elements.
pub ceiling: Au,
/// The maximum right position of the float, generally determined by the containing block.
pub max_width: Au,
/// The maximum inline-end position of the float, generally determined by the containing block.
pub max_inline_size: Au,
/// The kind of float.
pub kind: FloatKind
}
impl fmt::Show for PlacementInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "size={} ceiling={} max_width={} kind={:?}", self.size, self.ceiling, self.max_width, self.kind)
write!(f, "size={} ceiling={} max_inline_size={} kind={:?}", self.size, self.ceiling, self.max_inline_size, self.kind)
}
}
fn range_intersect(top_1: Au, bottom_1: Au, top_2: Au, bottom_2: Au) -> (Au, Au) {
(max(top_1, top_2), min(bottom_1, bottom_2))
fn range_intersect(block_start_1: Au, block_end_1: Au, block_start_2: Au, block_end_2: Au) -> (Au, Au) {
(max(block_start_1, block_start_2), min(block_end_1, block_end_2))
}
/// Encapsulates information about floats. This is optimized to avoid allocation if there are
@ -145,7 +144,8 @@ pub struct Floats {
/// The list of floats.
list: FloatListRef,
/// The offset of the flow relative to the first float.
offset: Point2D<Au>,
offset: LogicalSize<Au>,
pub writing_mode: WritingMode,
}
impl fmt::Show for Floats {
@ -163,79 +163,80 @@ impl fmt::Show for Floats {
impl Floats {
/// Creates a new `Floats` object.
pub fn new() -> Floats {
pub fn new(writing_mode: WritingMode) -> Floats {
Floats {
list: FloatListRef::new(),
offset: Point2D(Au(0), Au(0)),
offset: LogicalSize::zero(writing_mode),
writing_mode: writing_mode,
}
}
/// Adjusts the recorded offset of the flow relative to the first float.
pub fn translate(&mut self, delta: Point2D<Au>) {
pub fn translate(&mut self, delta: LogicalSize<Au>) {
self.offset = self.offset + delta
}
/// Returns the position of the last float in flow coordinates.
pub fn last_float_pos(&self) -> Option<Point2D<Au>> {
pub fn last_float_pos(&self) -> Option<LogicalPoint<Au>> {
match self.list.get() {
None => None,
Some(list) => {
match list.floats.last() {
None => None,
Some(float) => Some(float.bounds.origin + self.offset),
Some(float) => Some(float.bounds.start + self.offset),
}
}
}
}
/// Returns a rectangle that encloses the region from top to top + height, with width small
/// Returns a rectangle that encloses the region from block-start to block-start + block-size, with inline-size small
/// enough that it doesn't collide with any floats. max_x is the x-coordinate beyond which
/// floats have no effect. (Generally this is the containing block width.)
pub fn available_rect(&self, top: Au, height: Au, max_x: Au) -> Option<Rect<Au>> {
/// floats have no effect. (Generally this is the containing block inline-size.)
pub fn available_rect(&self, block_start: Au, block_size: Au, max_x: Au) -> Option<LogicalRect<Au>> {
let list = match self.list.get() {
None => return None,
Some(list) => list,
};
let top = top - self.offset.y;
let block_start = block_start - self.offset.block;
debug!("available_rect: trying to find space at {}", top);
debug!("available_rect: trying to find space at {}", block_start);
// Relevant dimensions for the right-most left float
let mut max_left = Au(0) - self.offset.x;
let mut l_top = None;
let mut l_bottom = None;
// Relevant dimensions for the left-most right float
let mut min_right = max_x - self.offset.x;
let mut r_top = None;
let mut r_bottom = None;
// Relevant dimensions for the inline-end-most inline-start float
let mut max_inline_start = Au(0) - self.offset.inline;
let mut l_block_start = None;
let mut l_block_end = None;
// Relevant dimensions for the inline-start-most inline-end float
let mut min_inline_end = max_x - self.offset.inline;
let mut r_block_start = None;
let mut r_block_end = None;
// Find the float collisions for the given vertical range.
for float in list.floats.iter() {
debug!("available_rect: Checking for collision against float");
let float_pos = float.bounds.origin;
let float_pos = float.bounds.start;
let float_size = float.bounds.size;
debug!("float_pos: {}, float_size: {}", float_pos, float_size);
match float.kind {
FloatLeft if float_pos.x + float_size.width > max_left &&
float_pos.y + float_size.height > top && float_pos.y < top + height => {
max_left = float_pos.x + float_size.width;
FloatLeft if float_pos.i + float_size.inline > max_inline_start &&
float_pos.b + float_size.block > block_start && float_pos.b < block_start + block_size => {
max_inline_start = float_pos.i + float_size.inline;
l_top = Some(float_pos.y);
l_bottom = Some(float_pos.y + float_size.height);
l_block_start = Some(float_pos.b);
l_block_end = Some(float_pos.b + float_size.block);
debug!("available_rect: collision with left float: new max_left is {}",
max_left);
debug!("available_rect: collision with inline_start float: new max_inline_start is {}",
max_inline_start);
}
FloatRight if float_pos.x < min_right &&
float_pos.y + float_size.height > top && float_pos.y < top + height => {
min_right = float_pos.x;
FloatRight if float_pos.i < min_inline_end &&
float_pos.b + float_size.block > block_start && float_pos.b < block_start + block_size => {
min_inline_end = float_pos.i;
r_top = Some(float_pos.y);
r_bottom = Some(float_pos.y + float_size.height);
debug!("available_rect: collision with right float: new min_right is {}",
min_right);
r_block_start = Some(float_pos.b);
r_block_end = Some(float_pos.b + float_size.block);
debug!("available_rect: collision with inline_end float: new min_inline_end is {}",
min_inline_end);
}
FloatLeft | FloatRight => {}
}
@ -243,29 +244,29 @@ impl Floats {
// Extend the vertical range of the rectangle to the closest floats.
// If there are floats on both sides, take the intersection of the
// two areas. Also make sure we never return a top smaller than the
// two areas. Also make sure we never return a block-start smaller than the
// given upper bound.
let (top, bottom) = match (r_top, r_bottom, l_top, l_bottom) {
(Some(r_top), Some(r_bottom), Some(l_top), Some(l_bottom)) =>
range_intersect(max(top, r_top), r_bottom, max(top, l_top), l_bottom),
let (block_start, block_end) = match (r_block_start, r_block_end, l_block_start, l_block_end) {
(Some(r_block_start), Some(r_block_end), Some(l_block_start), Some(l_block_end)) =>
range_intersect(max(block_start, r_block_start), r_block_end, max(block_start, l_block_start), l_block_end),
(None, None, Some(l_top), Some(l_bottom)) => (max(top, l_top), l_bottom),
(Some(r_top), Some(r_bottom), None, None) => (max(top, r_top), r_bottom),
(None, None, Some(l_block_start), Some(l_block_end)) => (max(block_start, l_block_start), l_block_end),
(Some(r_block_start), Some(r_block_end), None, None) => (max(block_start, r_block_start), r_block_end),
(None, None, None, None) => return None,
_ => fail!("Reached unreachable state when computing float area")
};
// FIXME(eatkinson): This assertion is too strong and fails in some cases. It is OK to
// return negative widths since we check against that right away, but we should still
// return negative inline-sizes since we check against that inline-end away, but we should still
// undersrtand why they occur and add a stronger assertion here.
// assert!(max_left < min_right);
// assert!(max_inline-start < min_inline-end);
assert!(top <= bottom, "Float position error");
assert!(block_start <= block_end, "Float position error");
Some(Rect {
origin: Point2D(max_left, top) + self.offset,
size: Size2D(min_right - max_left, bottom - top)
})
Some(LogicalRect::new(
self.writing_mode, max_inline_start + self.offset.inline, block_start + self.offset.block,
min_inline_end - max_inline_start, block_end - block_start
))
}
/// Adds a new float to the list.
@ -275,8 +276,8 @@ impl Floats {
let list = self.list.get_mut();
new_info = PlacementInfo {
size: info.size,
ceiling: max(info.ceiling, list.max_top + self.offset.y),
max_width: info.max_width,
ceiling: max(info.ceiling, list.max_block_start + self.offset.block),
max_inline_size: info.max_inline_size,
kind: info.kind
}
}
@ -284,109 +285,131 @@ impl Floats {
debug!("add_float: added float with info {:?}", new_info);
let new_float = Float {
bounds: Rect {
origin: self.place_between_floats(&new_info).origin - self.offset,
size: info.size,
},
bounds: LogicalRect::from_point_size(
self.writing_mode,
self.place_between_floats(&new_info).start - self.offset,
info.size,
),
kind: info.kind
};
let list = self.list.get_mut();
list.floats.push(new_float);
list.max_top = max(list.max_top, new_float.bounds.origin.y);
list.max_block_start = max(list.max_block_start, new_float.bounds.start.b);
}
/// Given the top 3 sides of the rectangle, finds the largest height that will result in the
/// rectangle not colliding with any floats. Returns None if that height is infinite.
fn max_height_for_bounds(&self, left: Au, top: Au, width: Au) -> Option<Au> {
/// Given the block-start 3 sides of the rectangle, finds the largest block-size that will result in the
/// rectangle not colliding with any floats. Returns None if that block-size is infinite.
fn max_block_size_for_bounds(&self, inline_start: Au, block_start: Au, inline_size: Au) -> Option<Au> {
let list = match self.list.get() {
None => return None,
Some(list) => list,
};
let top = top - self.offset.y;
let left = left - self.offset.x;
let mut max_height = None;
let block_start = block_start - self.offset.block;
let inline_start = inline_start - self.offset.inline;
let mut max_block_size = None;
for float in list.floats.iter() {
if float.bounds.origin.y + float.bounds.size.height > top &&
float.bounds.origin.x + float.bounds.size.width > left &&
float.bounds.origin.x < left + width {
let new_y = float.bounds.origin.y;
max_height = Some(min(max_height.unwrap_or(new_y), new_y));
if float.bounds.start.b + float.bounds.size.block > block_start &&
float.bounds.start.i + float.bounds.size.inline > inline_start &&
float.bounds.start.i < inline_start + inline_size {
let new_y = float.bounds.start.b;
max_block_size = Some(min(max_block_size.unwrap_or(new_y), new_y));
}
}
max_height.map(|h| h + self.offset.y)
max_block_size.map(|h| h + self.offset.block)
}
/// Given placement information, finds the closest place a fragment can be positioned without
/// colliding with any floats.
pub fn place_between_floats(&self, info: &PlacementInfo) -> Rect<Au> {
debug!("place_between_floats: Placing object with width {} and height {}",
info.size.width,
info.size.height);
pub fn place_between_floats(&self, info: &PlacementInfo) -> LogicalRect<Au> {
debug!("place_between_floats: Placing object with {}", info.size);
// If no floats, use this fast path.
if !self.list.is_present() {
match info.kind {
FloatLeft => {
return Rect(Point2D(Au(0), info.ceiling),
Size2D(info.max_width, Au(i32::MAX)))
return LogicalRect::new(
self.writing_mode,
Au(0),
info.ceiling,
info.max_inline_size,
Au(i32::MAX))
}
FloatRight => {
return Rect(Point2D(info.max_width - info.size.width, info.ceiling),
Size2D(info.max_width, Au(i32::MAX)))
return LogicalRect::new(
self.writing_mode,
info.max_inline_size - info.size.inline,
info.ceiling,
info.max_inline_size,
Au(i32::MAX))
}
}
}
// Can't go any higher than previous floats or previous elements in the document.
let mut float_y = info.ceiling;
let mut float_b = info.ceiling;
loop {
let maybe_location = self.available_rect(float_y, info.size.height, info.max_width);
debug!("place_float: Got available rect: {:?} for y-pos: {}", maybe_location, float_y);
let maybe_location = self.available_rect(float_b, info.size.block, info.max_inline_size);
debug!("place_float: Got available rect: {:?} for y-pos: {}", maybe_location, float_b);
match maybe_location {
// If there are no floats blocking us, return the current location
// TODO(eatkinson): integrate with overflow
None => {
return match info.kind {
FloatLeft => {
Rect(Point2D(Au(0), float_y),
Size2D(info.max_width, Au(i32::MAX)))
LogicalRect::new(
self.writing_mode,
Au(0),
float_b,
info.max_inline_size,
Au(i32::MAX))
}
FloatRight => {
Rect(Point2D(info.max_width - info.size.width, float_y),
Size2D(info.max_width, Au(i32::MAX)))
LogicalRect::new(
self.writing_mode,
info.max_inline_size - info.size.inline,
float_b,
info.max_inline_size,
Au(i32::MAX))
}
}
}
Some(rect) => {
assert!(rect.origin.y + rect.size.height != float_y,
assert!(rect.start.b + rect.size.block != float_b,
"Non-terminating float placement");
// Place here if there is enough room
if rect.size.width >= info.size.width {
let height = self.max_height_for_bounds(rect.origin.x,
rect.origin.y,
rect.size.width);
let height = height.unwrap_or(Au(i32::MAX));
if rect.size.inline >= info.size.inline {
let block_size = self.max_block_size_for_bounds(rect.start.i,
rect.start.b,
rect.size.inline);
let block_size = block_size.unwrap_or(Au(i32::MAX));
return match info.kind {
FloatLeft => {
Rect(Point2D(rect.origin.x, float_y),
Size2D(rect.size.width, height))
LogicalRect::new(
self.writing_mode,
rect.start.i,
float_b,
rect.size.inline,
block_size)
}
FloatRight => {
Rect(Point2D(rect.origin.x + rect.size.width - info.size.width,
float_y),
Size2D(rect.size.width, height))
LogicalRect::new(
self.writing_mode,
rect.start.i + rect.size.inline - info.size.inline,
float_b,
rect.size.inline,
block_size)
}
}
}
// Try to place at the next-lowest location.
// Need to be careful of fencepost errors.
float_y = rect.origin.y + rect.size.height;
float_b = rect.start.b + rect.size.block;
}
}
}
@ -404,8 +427,8 @@ impl Floats {
(ClearLeft, FloatLeft) |
(ClearRight, FloatRight) |
(ClearBoth, _) => {
let y = self.offset.y + float.bounds.origin.y + float.bounds.size.height;
clearance = max(clearance, y);
let b = self.offset.block + float.bounds.start.b + float.bounds.size.block;
clearance = max(clearance, b);
}
_ => {}
}

Просмотреть файл

@ -34,7 +34,7 @@ use flow_ref::FlowRef;
use fragment::{Fragment, TableRowFragment, TableCellFragment};
use incremental::RestyleDamage;
use inline::InlineFlow;
use model::{CollapsibleMargins, IntrinsicWidths, MarginCollapseInfo};
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
use parallel::FlowParallelInfo;
use table_wrapper::TableWrapperFlow;
use table::TableFlow;
@ -46,17 +46,15 @@ use table_cell::TableCellFlow;
use wrapper::ThreadSafeLayoutNode;
use collections::dlist::DList;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::display_list::DisplayList;
use gfx::render_task::RenderLayer;
use servo_msg::compositor_msg::LayerId;
use servo_util::geometry::Au;
use servo_util::logical_geometry::WritingMode;
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
use std::mem;
use std::fmt;
use std::iter::Zip;
use std::num::Zero;
use std::sync::atomics::{AtomicUint, Relaxed, SeqCst};
use std::slice::MutItems;
use style::computed_values::{clear, position, text_align};
@ -125,54 +123,54 @@ pub trait Flow: fmt::Show + ToStr + Share {
fail!("called as_table_cell() on a non-tablecell flow")
}
/// If this is a table row or table rowgroup or table flow, returns column widths.
/// If this is a table row or table rowgroup or table flow, returns column inline-sizes.
/// Fails otherwise.
fn col_widths<'a>(&'a mut self) -> &'a mut Vec<Au> {
fail!("called col_widths() on an other flow than table-row/table-rowgroup/table")
fn col_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<Au> {
fail!("called col_inline_sizes() on an other flow than table-row/table-rowgroup/table")
}
/// If this is a table row flow or table rowgroup flow or table flow, returns column min widths.
/// If this is a table row flow or table rowgroup flow or table flow, returns column min inline-sizes.
/// Fails otherwise.
fn col_min_widths<'a>(&'a self) -> &'a Vec<Au> {
fail!("called col_min_widths() on an other flow than table-row/table-rowgroup/table")
fn col_min_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
fail!("called col_min_inline_sizes() on an other flow than table-row/table-rowgroup/table")
}
/// If this is a table row flow or table rowgroup flow or table flow, returns column min widths.
/// If this is a table row flow or table rowgroup flow or table flow, returns column min inline-sizes.
/// Fails otherwise.
fn col_pref_widths<'a>(&'a self) -> &'a Vec<Au> {
fail!("called col_pref_widths() on an other flow than table-row/table-rowgroup/table")
fn col_pref_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
fail!("called col_pref_inline_sizes() on an other flow than table-row/table-rowgroup/table")
}
// Main methods
/// Pass 1 of reflow: computes minimum and preferred widths.
/// Pass 1 of reflow: computes minimum and preferred inline-sizes.
///
/// Recursively (bottom-up) determine the flow's minimum and preferred widths. When called on
/// this flow, all child flows have had their minimum and preferred widths set. This function
/// must decide minimum/preferred widths based on its children's widths and the dimensions of
/// Recursively (bottom-up) determine the flow's minimum and preferred inline-sizes. When called on
/// this flow, all child flows have had their minimum and preferred inline-sizes set. This function
/// must decide minimum/preferred inline-sizes based on its children's inline-sizes and the dimensions of
/// any boxes it is responsible for flowing.
fn bubble_widths(&mut self, _ctx: &mut LayoutContext) {
fail!("bubble_widths not yet implemented")
fn bubble_inline_sizes(&mut self, _ctx: &mut LayoutContext) {
fail!("bubble_inline_sizes not yet implemented")
}
/// Pass 2 of reflow: computes width.
fn assign_widths(&mut self, _ctx: &mut LayoutContext) {
fail!("assign_widths not yet implemented")
/// Pass 2 of reflow: computes inline-size.
fn assign_inline_sizes(&mut self, _ctx: &mut LayoutContext) {
fail!("assign_inline_sizes not yet implemented")
}
/// Pass 3a of reflow: computes height.
fn assign_height(&mut self, _ctx: &mut LayoutContext) {
fail!("assign_height not yet implemented")
/// Pass 3a of reflow: computes block-size.
fn assign_block_size(&mut self, _ctx: &mut LayoutContext) {
fail!("assign_block_size not yet implemented")
}
/// Assigns heights in-order; or, if this is a float, places the float. The default
/// implementation simply assigns heights if this flow is impacted by floats. Returns true if
/// Assigns block-sizes in-order; or, if this is a float, places the float. The default
/// implementation simply assigns block-sizes if this flow is impacted by floats. Returns true if
/// this child was impacted by floats or false otherwise.
fn assign_height_for_inorder_child_if_necessary(&mut self, layout_context: &mut LayoutContext)
fn assign_block_size_for_inorder_child_if_necessary(&mut self, layout_context: &mut LayoutContext)
-> bool {
let impacted = base(&*self).flags.impacted_by_floats();
if impacted {
self.assign_height(layout_context);
self.assign_block_size(layout_context);
}
impacted
}
@ -193,7 +191,7 @@ pub trait Flow: fmt::Show + ToStr + Share {
false
}
fn compute_collapsible_top_margin(&mut self,
fn compute_collapsible_block_start_margin(&mut self,
_layout_context: &mut LayoutContext,
_margin_collapse_info: &mut MarginCollapseInfo) {
// The default implementation is a no-op.
@ -256,7 +254,7 @@ pub trait Flow: fmt::Show + ToStr + Share {
/// Return the dimensions of the containing block generated by this flow for absolutely-
/// positioned descendants. For block flows, this is the padding box.
fn generated_containing_block_rect(&self) -> Rect<Au> {
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
fail!("generated_containing_block_position not yet implemented for this flow")
}
@ -443,11 +441,11 @@ bitfield!(FlowFlags, has_left_floated_descendants, set_has_left_floated_descenda
bitfield!(FlowFlags, has_right_floated_descendants, set_has_right_floated_descendants, 0b0000_0010)
// Whether this flow is impacted by floats to the left in the same block formatting context (i.e.
// its height depends on some prior flows with `float: left`).
// its block-size depends on some prior flows with `float: left`).
bitfield!(FlowFlags, impacted_by_left_floats, set_impacted_by_left_floats, 0b0000_0100)
// Whether this flow is impacted by floats to the right in the same block formatting context (i.e.
// its height depends on some prior flows with `float: right`).
// its block-size depends on some prior flows with `float: right`).
bitfield!(FlowFlags, impacted_by_right_floats, set_impacted_by_right_floats, 0b0000_1000)
/// The bitmask of flags that represent the text alignment field.
@ -526,14 +524,14 @@ pub struct Descendants {
descendant_links: Vec<FlowRef>,
/// Static y offsets of all descendants from the start of this flow box.
pub static_y_offsets: Vec<Au>,
pub static_b_offsets: Vec<Au>,
}
impl Descendants {
pub fn new() -> Descendants {
Descendants {
descendant_links: Vec::new(),
static_y_offsets: Vec::new(),
static_b_offsets: Vec::new(),
}
}
@ -566,7 +564,7 @@ impl Descendants {
let descendant_iter = DescendantIter {
iter: self.descendant_links.mut_slice_from(0).mut_iter(),
};
descendant_iter.zip(self.static_y_offsets.mut_slice_from(0).mut_iter())
descendant_iter.zip(self.static_b_offsets.mut_slice_from(0).mut_iter())
}
}
@ -596,9 +594,9 @@ pub type DescendantOffsetIter<'a> = Zip<DescendantIter<'a>, MutItems<'a, Au>>;
/// confused with absolutely-positioned flows).
pub struct AbsolutePositionInfo {
/// The size of the containing block for relatively-positioned descendants.
pub relative_containing_block_size: Size2D<Au>,
pub relative_containing_block_size: LogicalSize<Au>,
/// The position of the absolute containing block.
pub absolute_containing_block_position: Point2D<Au>,
pub absolute_containing_block_position: LogicalPoint<Au>,
/// Whether the absolute containing block forces positioned descendants to be layerized.
///
/// FIXME(pcwalton): Move into `FlowFlags`.
@ -606,12 +604,12 @@ pub struct AbsolutePositionInfo {
}
impl AbsolutePositionInfo {
pub fn new() -> AbsolutePositionInfo {
// FIXME(pcwalton): The initial relative containing block size should be equal to the size
pub fn new(writing_mode: WritingMode) -> AbsolutePositionInfo {
// FIXME(pcwalton): The initial relative containing block-size should be equal to the size
// of the root layer.
AbsolutePositionInfo {
relative_containing_block_size: Size2D::zero(),
absolute_containing_block_position: Zero::zero(),
relative_containing_block_size: LogicalSize::zero(writing_mode),
absolute_containing_block_position: LogicalPoint::zero(writing_mode),
layers_needed_for_positioned_flows: false,
}
}
@ -634,7 +632,7 @@ pub struct BaseFlow {
/* layout computations */
// TODO: min/pref and position are used during disjoint phases of
// layout; maybe combine into a single enum to save space.
pub intrinsic_widths: IntrinsicWidths,
pub intrinsic_inline_sizes: IntrinsicISizes,
/// The upper left corner of the box representing this flow, relative to the box representing
/// its parent flow.
@ -644,11 +642,11 @@ pub struct BaseFlow {
/// This does not include margins in the block flow direction, because those can collapse. So
/// for the block direction (usually vertical), this represents the *border box*. For the
/// inline direction (usually horizontal), this represents the *margin box*.
pub position: Rect<Au>,
pub position: LogicalRect<Au>,
/// The amount of overflow of this flow, relative to the containing block. Must include all the
/// pixels of all the display list items for correct invalidation.
pub overflow: Rect<Au>,
pub overflow: LogicalRect<Au>,
/// Data used during parallel traversals.
///
@ -662,7 +660,7 @@ pub struct BaseFlow {
pub collapsible_margins: CollapsibleMargins,
/// The position of this flow in page coordinates, computed during display list construction.
pub abs_position: Point2D<Au>,
pub abs_position: LogicalPoint<Au>,
/// Details about descendants with position 'absolute' or 'fixed' for which we are the
/// containing block. This is in tree order. This includes any direct children.
@ -670,10 +668,10 @@ pub struct BaseFlow {
/// Offset wrt the nearest positioned ancestor - aka the Containing Block
/// for any absolutely positioned elements.
pub absolute_static_x_offset: Au,
pub absolute_static_i_offset: Au,
/// Offset wrt the Initial Containing Block.
pub fixed_static_x_offset: Au,
pub fixed_static_i_offset: Au,
/// Reference to the Containing Block, if this flow is absolutely positioned.
pub absolute_cb: ContainingBlockLink,
@ -681,7 +679,7 @@ pub struct BaseFlow {
/// Information needed to compute absolute (i.e. viewport-relative) flow positions (not to be
/// confused with absolutely-positioned flows).
///
/// FIXME(pcwalton): Merge with `absolute_static_x_offset` and `fixed_static_x_offset` above?
/// FIXME(pcwalton): Merge with `absolute_static_i_offset` and `fixed_static_i_offset` above?
pub absolute_position_info: AbsolutePositionInfo,
/// The unflattened display items for this flow.
@ -692,6 +690,8 @@ pub struct BaseFlow {
/// Various flags for flows, tightly packed to save space.
pub flags: FlowFlags,
pub writing_mode: WritingMode,
}
#[unsafe_destructor]
@ -706,6 +706,7 @@ impl Drop for BaseFlow {
impl BaseFlow {
#[inline]
pub fn new(node: ThreadSafeLayoutNode) -> BaseFlow {
let writing_mode = node.style().writing_mode;
BaseFlow {
ref_count: AtomicUint::new(1),
@ -715,24 +716,25 @@ impl BaseFlow {
next_sibling: None,
prev_sibling: None,
intrinsic_widths: IntrinsicWidths::new(),
position: Rect::zero(),
overflow: Rect::zero(),
intrinsic_inline_sizes: IntrinsicISizes::new(),
position: LogicalRect::zero(writing_mode),
overflow: LogicalRect::zero(writing_mode),
parallel: FlowParallelInfo::new(),
floats: Floats::new(),
floats: Floats::new(writing_mode),
collapsible_margins: CollapsibleMargins::new(),
abs_position: Point2D(Au::new(0), Au::new(0)),
abs_position: LogicalPoint::zero(writing_mode),
abs_descendants: Descendants::new(),
absolute_static_x_offset: Au::new(0),
fixed_static_x_offset: Au::new(0),
absolute_static_i_offset: Au::new(0),
fixed_static_i_offset: Au::new(0),
absolute_cb: ContainingBlockLink::new(),
display_list: DisplayList::new(),
layers: DList::new(),
absolute_position_info: AbsolutePositionInfo::new(),
absolute_position_info: AbsolutePositionInfo::new(writing_mode),
flags: FlowFlags::new(),
writing_mode: writing_mode,
}
}
@ -973,14 +975,14 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
continue;
}
let mut kid_overflow = base(kid).overflow;
kid_overflow = kid_overflow.translate(&my_position.origin);
kid_overflow = kid_overflow.translate(&my_position.start);
overflow = overflow.union(&kid_overflow)
}
// FIXME(#2004, pcwalton): This is wrong for `position: fixed`.
for descendant_link in mut_base(self).abs_descendants.iter() {
let mut kid_overflow = base(descendant_link).overflow;
kid_overflow = kid_overflow.translate(&my_position.origin);
kid_overflow = kid_overflow.translate(&my_position.start);
overflow = overflow.union(&kid_overflow)
}
}
@ -1076,7 +1078,7 @@ impl ContainingBlockLink {
}
#[inline]
pub fn generated_containing_block_rect(&mut self) -> Rect<Au> {
pub fn generated_containing_block_rect(&mut self) -> LogicalRect<Au> {
match self.link {
None => fail!("haven't done it"),
Some(ref mut link) => link.get_mut().generated_containing_block_rect(),

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -11,12 +11,12 @@ bitflags! {
#[doc = "Currently unused; need to decide how this propagates."]
static Repaint = 0x01,
#[doc = "Recompute intrinsic widths (minimum and preferred)."]
#[doc = "Recompute intrinsic inline_sizes (minimum and preferred)."]
#[doc = "Propagates down the flow tree because the computation is"]
#[doc = "bottom-up."]
static BubbleWidths = 0x02,
static BubbleISizes = 0x02,
#[doc = "Recompute actual widths and heights."]
#[doc = "Recompute actual inline_sizes and block_sizes."]
#[doc = "Propagates up the flow tree because the computation is"]
#[doc = "top-down."]
static Reflow = 0x04
@ -31,7 +31,7 @@ impl RestyleDamage {
/// Elements of self which should also get set on any child flows.
pub fn propagate_down(self) -> RestyleDamage {
self & BubbleWidths
self & BubbleISizes
}
}
@ -61,7 +61,7 @@ pub fn compute_damage(old: &ComputedValues, new: &ComputedValues) -> RestyleDama
get_border.border_top_color, get_border.border_right_color,
get_border.border_bottom_color, get_border.border_left_color ]);
add_if_not_equal!(old, new, damage, [ Repaint, BubbleWidths, Reflow ],
add_if_not_equal!(old, new, damage, [ Repaint, BubbleISizes, Reflow ],
[ get_border.border_top_width, get_border.border_right_width,
get_border.border_bottom_width, get_border.border_left_width,
get_margin.margin_top, get_margin.margin_right,

Просмотреть файл

@ -10,19 +10,20 @@ use floats::{FloatLeft, Floats, PlacementInfo};
use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass};
use flow;
use fragment::{Fragment, ScannedTextFragment, ScannedTextFragmentInfo, SplitInfo};
use model::IntrinsicWidths;
use model::IntrinsicISizes;
use model;
use text;
use wrapper::ThreadSafeLayoutNode;
use collections::{Deque, RingBuf};
use geom::{Point2D, Rect, SideOffsets2D, Size2D};
use geom::Size2D;
use gfx::display_list::ContentLevel;
use gfx::font::FontMetrics;
use gfx::font_context::FontContext;
use gfx::text::glyph::CharIndex;
use servo_util::geometry::Au;
use servo_util::geometry;
use servo_util::logical_geometry::{LogicalRect, LogicalMargin, LogicalSize};
use servo_util::range;
use servo_util::range::{EachIndex, Range, RangeIndex, IntRangeIndex};
use std::iter::Enumerate;
@ -57,8 +58,8 @@ use sync::Arc;
///
/// Line fragments also contain some metadata used during line breaking. The
/// green zone is the area that the line can expand to before it collides
/// with a float or a horizontal wall of the containing block. The top
/// left corner of the green zone is the same as that of the line, but
/// 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
/// the green zone can be taller and wider than the line itself.
pub struct Line {
/// A range of line indices that describe line breaks.
@ -109,16 +110,16 @@ pub struct Line {
/// | v |
/// |< - origin.x ->+ - - - - - - - - +---------+---- |
/// | | | | ^ |
/// | | | <img> | size.height |
/// | | | <img> | size.block-size |
/// | I like truffles, | | v |
/// | + - - - - - - - - +---------+---- |
/// | | | |
/// | |<------ size.width ------->| |
/// | |<------ size.inline-size ------->| |
/// | |
/// | |
/// +-----------------------------------------------------------+
/// ~~~
pub bounds: Rect<Au>,
pub bounds: LogicalRect<Au>,
/// The green zone is the greatest extent from wich a line can extend to
/// before it collides with a float.
///
@ -140,7 +141,7 @@ pub struct Line {
/// ::: green zone
/// FFF float
/// ~~~
pub green_zone: Size2D<Au>
pub green_zone: LogicalSize<Au>
}
int_range_index! {
@ -263,22 +264,22 @@ struct LineBreaker {
pub work_list: RingBuf<Fragment>,
pub pending_line: Line,
pub lines: Vec<Line>,
pub cur_y: Au,
pub cur_b: Au, // Current position on the block direction
}
impl LineBreaker {
pub fn new(float_ctx: Floats) -> LineBreaker {
LineBreaker {
floats: float_ctx,
new_fragments: Vec::new(),
work_list: RingBuf::new(),
pending_line: Line {
range: Range::empty(),
bounds: Rect(Point2D(Au::new(0), Au::new(0)), Size2D(Au::new(0), Au::new(0))),
green_zone: Size2D(Au::new(0), Au::new(0))
bounds: LogicalRect::zero(float_ctx.writing_mode),
green_zone: LogicalSize::zero(float_ctx.writing_mode)
},
floats: float_ctx,
lines: Vec::new(),
cur_y: Au::new(0)
cur_b: Au::new(0)
}
}
@ -290,14 +291,15 @@ impl LineBreaker {
debug!("Resetting LineBreaker's state for flow.");
self.lines = Vec::new();
self.new_fragments = Vec::new();
self.cur_y = Au(0);
self.cur_b = Au(0);
self.reset_line();
}
fn reset_line(&mut self) {
self.pending_line.range.reset(num::zero(), num::zero());
self.pending_line.bounds = Rect(Point2D(Au::new(0), self.cur_y), Size2D(Au::new(0), Au::new(0)));
self.pending_line.green_zone = Size2D(Au::new(0), Au::new(0))
self.pending_line.bounds = LogicalRect::new(
self.floats.writing_mode, Au::new(0), self.cur_b, Au::new(0), Au::new(0));
self.pending_line.green_zone = LogicalSize::zero(self.floats.writing_mode)
}
pub fn scan_for_lines(&mut self, flow: &mut InlineFlow) {
@ -340,7 +342,7 @@ impl LineBreaker {
}
if self.pending_line.range.length() > num::zero() {
debug!("LineBreaker: Partially full line {:u} left at end of scanning.",
debug!("LineBreaker: Partially full line {:u} inline_start at end of scanning.",
self.lines.len());
self.flush_current_line();
}
@ -358,45 +360,46 @@ impl LineBreaker {
// clear line and add line mapping
debug!("LineBreaker: Saving information for flushed line {:u}.", self.lines.len());
self.lines.push(self.pending_line);
self.cur_y = self.pending_line.bounds.origin.y + self.pending_line.bounds.size.height;
self.cur_b = self.pending_line.bounds.start.b + self.pending_line.bounds.size.block;
self.reset_line();
}
// FIXME(eatkinson): this assumes that the tallest fragment in the line determines the line height
// FIXME(eatkinson): this assumes that the tallest fragment in the line determines the line block-size
// This might not be the case with some weird text fonts.
fn new_height_for_line(&self, new_fragment: &Fragment) -> Au {
let fragment_height = new_fragment.content_height();
if fragment_height > self.pending_line.bounds.size.height {
fragment_height
fn new_block_size_for_line(&self, new_fragment: &Fragment) -> Au {
let fragment_block_size = new_fragment.content_block_size();
if fragment_block_size > self.pending_line.bounds.size.block {
fragment_block_size
} else {
self.pending_line.bounds.size.height
self.pending_line.bounds.size.block
}
}
/// Computes the position of a line that has only the provided fragment. Returns the bounding
/// rect of the line's green zone (whose origin coincides with the line's origin) and the actual
/// width of the first fragment after splitting.
/// inline-size of the first fragment after splitting.
fn initial_line_placement(&self, first_fragment: &Fragment, ceiling: Au, flow: &InlineFlow)
-> (Rect<Au>, Au) {
-> (LogicalRect<Au>, Au) {
debug!("LineBreaker: Trying to place first fragment of line {}", self.lines.len());
let first_fragment_size = first_fragment.border_box.size;
let splittable = first_fragment.can_split();
debug!("LineBreaker: fragment size: {}, splittable: {}", first_fragment_size, splittable);
// Initally, pretend a splittable fragment has 0 width.
// We will move it later if it has nonzero width
// Initally, pretend a splittable fragment has 0 inline-size.
// We will move it later if it has nonzero inline-size
// and that causes problems.
let placement_width = if splittable {
let placement_inline_size = if splittable {
Au::new(0)
} else {
first_fragment_size.width
first_fragment_size.inline
};
let info = PlacementInfo {
size: Size2D(placement_width, first_fragment_size.height),
size: LogicalSize::new(
self.floats.writing_mode, placement_inline_size, first_fragment_size.block),
ceiling: ceiling,
max_width: flow.base.position.size.width,
max_inline_size: flow.base.position.size.inline,
kind: FloatLeft,
};
@ -407,24 +410,24 @@ impl LineBreaker {
info);
// Simple case: if the fragment fits, then we can stop here
if line_bounds.size.width > first_fragment_size.width {
if line_bounds.size.inline > first_fragment_size.inline {
debug!("LineBreaker: case=fragment fits");
return (line_bounds, first_fragment_size.width);
return (line_bounds, first_fragment_size.inline);
}
// If not, but we can't split the fragment, then we'll place
// the line here and it will overflow.
if !splittable {
debug!("LineBreaker: case=line doesn't fit, but is unsplittable");
return (line_bounds, first_fragment_size.width);
return (line_bounds, first_fragment_size.inline);
}
debug!("LineBreaker: used to call split_to_width here");
return (line_bounds, first_fragment_size.width);
debug!("LineBreaker: used to call split_to_inline_size here");
return (line_bounds, first_fragment_size.inline);
}
/// Performs float collision avoidance. This is called when adding a fragment is going to increase
/// the height, and because of that we will collide with some floats.
/// the block-size, and because of that we will collide with some floats.
///
/// We have two options here:
/// 1) Move the entire line so that it doesn't collide any more.
@ -440,23 +443,23 @@ impl LineBreaker {
fn avoid_floats(&mut self,
in_fragment: Fragment,
flow: &InlineFlow,
new_height: Au,
new_block_size: Au,
line_is_empty: bool)
-> bool {
debug!("LineBreaker: entering float collision avoider!");
// First predict where the next line is going to be.
let this_line_y = self.pending_line.bounds.origin.y;
let (next_line, first_fragment_width) = self.initial_line_placement(&in_fragment, this_line_y, flow);
let this_line_y = self.pending_line.bounds.start.b;
let (next_line, first_fragment_inline_size) = self.initial_line_placement(&in_fragment, this_line_y, flow);
let next_green_zone = next_line.size;
let new_width = self.pending_line.bounds.size.width + first_fragment_width;
let new_inline_size = self.pending_line.bounds.size.inline + first_fragment_inline_size;
// Now, see if everything can fit at the new location.
if next_green_zone.width >= new_width && next_green_zone.height >= new_height {
if next_green_zone.inline >= new_inline_size && next_green_zone.block >= new_block_size {
debug!("LineBreaker: case=adding fragment collides vertically with floats: moving line");
self.pending_line.bounds.origin = next_line.origin;
self.pending_line.bounds.start = next_line.start;
self.pending_line.green_zone = next_green_zone;
assert!(!line_is_empty, "Non-terminating line breaking");
@ -478,29 +481,31 @@ impl LineBreaker {
} else {
debug!("LineBreaker: Found a new-line character, so splitting theline.");
let (left, right, run) = in_fragment.find_split_info_by_new_line()
let (inline_start, inline_end, run) = in_fragment.find_split_info_by_new_line()
.expect("LineBreaker: This split case makes no sense!");
let writing_mode = self.floats.writing_mode;
// TODO(bjz): Remove fragment splitting
let split_fragment = |split: SplitInfo| {
let info = ScannedTextFragmentInfo::new(run.clone(), split.range);
let specific = ScannedTextFragment(info);
let size = Size2D(split.width, in_fragment.border_box.size.height);
let size = LogicalSize::new(
writing_mode, split.inline_size, in_fragment.border_box.size.block);
in_fragment.transform(size, specific)
};
debug!("LineBreaker: Pushing the fragment to the left of the new-line character \
debug!("LineBreaker: Pushing the fragment to the inline_start of the new-line character \
to the line.");
let mut left = split_fragment(left);
left.new_line_pos = vec![];
self.push_fragment_to_line(left);
let mut inline_start = split_fragment(inline_start);
inline_start.new_line_pos = vec![];
self.push_fragment_to_line(inline_start);
for right in right.move_iter() {
debug!("LineBreaker: Deferring the fragment to the right of the new-line \
for inline_end in inline_end.move_iter() {
debug!("LineBreaker: Deferring the fragment to the inline_end of the new-line \
character to the line.");
let mut right = split_fragment(right);
right.new_line_pos = in_fragment.new_line_pos.clone();
self.work_list.push_front(right);
let mut inline_end = split_fragment(inline_end);
inline_end.new_line_pos = in_fragment.new_line_pos.clone();
self.work_list.push_front(inline_end);
}
false
}
@ -511,8 +516,8 @@ impl LineBreaker {
fn try_append_to_line(&mut self, in_fragment: Fragment, flow: &InlineFlow) -> bool {
let line_is_empty = self.pending_line.range.length() == num::zero();
if line_is_empty {
let (line_bounds, _) = self.initial_line_placement(&in_fragment, self.cur_y, flow);
self.pending_line.bounds.origin = line_bounds.origin;
let (line_bounds, _) = self.initial_line_placement(&in_fragment, self.cur_b, flow);
self.pending_line.bounds.start = line_bounds.start;
self.pending_line.green_zone = line_bounds.size;
}
@ -525,22 +530,22 @@ impl LineBreaker {
let green_zone = self.pending_line.green_zone;
// NB: At this point, if `green_zone.width < self.pending_line.bounds.size.width` or
// `green_zone.height < self.pending_line.bounds.size.height`, then we committed a line
// NB: At this point, if `green_zone.inline-size < self.pending_line.bounds.size.inline-size` or
// `green_zone.block-size < self.pending_line.bounds.size.block-size`, then we committed a line
// that overlaps with floats.
let new_height = self.new_height_for_line(&in_fragment);
if new_height > green_zone.height {
let new_block_size = self.new_block_size_for_line(&in_fragment);
if new_block_size > green_zone.block {
// Uh-oh. Float collision imminent. Enter the float collision avoider
return self.avoid_floats(in_fragment, flow, new_height, line_is_empty)
return self.avoid_floats(in_fragment, flow, new_block_size, line_is_empty)
}
// If we're not going to overflow the green zone vertically, we might still do so
// horizontally. We'll try to place the whole fragment on this line and break somewhere if it
// doesn't fit.
let new_width = self.pending_line.bounds.size.width + in_fragment.border_box.size.width;
if new_width <= green_zone.width {
let new_inline_size = self.pending_line.bounds.size.inline + in_fragment.border_box.size.inline;
if new_inline_size <= green_zone.inline {
debug!("LineBreaker: case=fragment fits without splitting");
self.push_fragment_to_line(in_fragment);
return true
@ -557,19 +562,20 @@ impl LineBreaker {
}
}
let available_width = green_zone.width - self.pending_line.bounds.size.width;
let split = in_fragment.find_split_info_for_width(CharIndex(0), available_width, line_is_empty);
match split.map(|(left, right, run)| {
let available_inline_size = green_zone.inline - self.pending_line.bounds.size.inline;
let split = in_fragment.find_split_info_for_inline_size(CharIndex(0), available_inline_size, line_is_empty);
match split.map(|(inline_start, inline_end, run)| {
// TODO(bjz): Remove fragment splitting
let split_fragment = |split: SplitInfo| {
let info = ScannedTextFragmentInfo::new(run.clone(), split.range);
let specific = ScannedTextFragment(info);
let size = Size2D(split.width, in_fragment.border_box.size.height);
let size = LogicalSize::new(
self.floats.writing_mode, split.inline_size, in_fragment.border_box.size.block);
in_fragment.transform(size, specific)
};
(left.map(|x| { debug!("LineBreaker: Left split {}", x); split_fragment(x) }),
right.map(|x| { debug!("LineBreaker: Right split {}", x); split_fragment(x) }))
(inline_start.map(|x| { debug!("LineBreaker: Left split {}", x); split_fragment(x) }),
inline_end.map(|x| { debug!("LineBreaker: Right split {}", x); split_fragment(x) }))
}) {
None => {
debug!("LineBreaker: Tried to split unsplittable render fragment! Deferring to next \
@ -577,21 +583,21 @@ impl LineBreaker {
self.work_list.push_front(in_fragment);
false
},
Some((Some(left_fragment), Some(right_fragment))) => {
debug!("LineBreaker: Line break found! Pushing left fragment to line and deferring \
right fragment to next line.");
self.push_fragment_to_line(left_fragment);
self.work_list.push_front(right_fragment);
Some((Some(inline_start_fragment), Some(inline_end_fragment))) => {
debug!("LineBreaker: Line break found! Pushing inline_start fragment to line and deferring \
inline_end fragment to next line.");
self.push_fragment_to_line(inline_start_fragment);
self.work_list.push_front(inline_end_fragment);
true
},
Some((Some(left_fragment), None)) => {
debug!("LineBreaker: Pushing left fragment to line.");
self.push_fragment_to_line(left_fragment);
Some((Some(inline_start_fragment), None)) => {
debug!("LineBreaker: Pushing inline_start fragment to line.");
self.push_fragment_to_line(inline_start_fragment);
true
},
Some((None, Some(right_fragment))) => {
debug!("LineBreaker: Pushing right fragment to line.");
self.push_fragment_to_line(right_fragment);
Some((None, Some(inline_end_fragment))) => {
debug!("LineBreaker: Pushing inline_end fragment to line.");
self.push_fragment_to_line(inline_end_fragment);
true
},
Some((None, None)) => {
@ -619,10 +625,10 @@ impl LineBreaker {
fragment_index: FragmentIndex(1),
char_index: CharIndex(0) /* unused for now */ ,
});
self.pending_line.bounds.size.width = self.pending_line.bounds.size.width +
fragment.border_box.size.width;
self.pending_line.bounds.size.height = Au::max(self.pending_line.bounds.size.height,
fragment.border_box.size.height);
self.pending_line.bounds.size.inline = self.pending_line.bounds.size.inline +
fragment.border_box.size.inline;
self.pending_line.bounds.size.block = Au::max(self.pending_line.bounds.size.block,
fragment.border_box.size.block);
self.new_fragments.push(fragment);
}
}
@ -901,11 +907,11 @@ pub struct InlineFlow {
/// lines.
pub lines: Vec<Line>,
/// The minimum height above the baseline for each line, as specified by the line height and
/// The minimum block-size above the baseline for each line, as specified by the line block-size and
/// font style.
pub minimum_height_above_baseline: Au,
pub minimum_block_size_above_baseline: Au,
/// The minimum depth below the baseline for each line, as specified by the line height and
/// The minimum depth below the baseline for each line, as specified by the line block-size and
/// font style.
pub minimum_depth_below_baseline: Au,
}
@ -916,14 +922,18 @@ impl InlineFlow {
base: BaseFlow::new(node),
fragments: fragments,
lines: Vec::new(),
minimum_height_above_baseline: Au(0),
minimum_block_size_above_baseline: Au(0),
minimum_depth_below_baseline: Au(0),
}
}
pub fn build_display_list_inline(&mut self, layout_context: &LayoutContext) {
let abs_rect = Rect(self.base.abs_position, self.base.position.size);
if !abs_rect.intersects(&layout_context.dirty) {
let abs_rect = LogicalRect::from_point_size(
self.base.writing_mode, self.base.abs_position, self.base.position.size);
// FIXME(#2795): Get the real container size
let container_size = Size2D::zero();
if !abs_rect.to_physical(self.base.writing_mode, container_size)
.intersects(&layout_context.dirty) {
return
}
@ -949,31 +959,31 @@ impl InlineFlow {
// For now, don't traverse the subtree rooted here.
}
/// Returns the distance from the baseline for the logical top left corner of this fragment,
/// Returns the distance from the baseline for the logical block-start inline-start corner of this fragment,
/// taking into account the value of the CSS `vertical-align` property. Negative values mean
/// "toward the logical top" and positive values mean "toward the logical bottom".
/// "toward the logical block-start" and positive values mean "toward the logical block-end".
///
/// The extra boolean is set if and only if `biggest_top` and/or `biggest_bottom` were updated.
/// That is, if the box has a `top` or `bottom` value, true is returned.
/// The extra boolean is set if and only if `biggest_block-start` and/or `biggest_block-end` were updated.
/// That is, if the box has a `block-start` or `block-end` value, true is returned.
fn distance_from_baseline(fragment: &Fragment,
ascent: Au,
parent_text_top: Au,
parent_text_bottom: Au,
height_above_baseline: &mut Au,
parent_text_block_start: Au,
parent_text_block_end: Au,
block_size_above_baseline: &mut Au,
depth_below_baseline: &mut Au,
largest_height_for_top_fragments: &mut Au,
largest_height_for_bottom_fragments: &mut Au)
largest_block_size_for_top_fragments: &mut Au,
largest_block_size_for_bottom_fragments: &mut Au)
-> (Au, bool) {
match fragment.vertical_align() {
vertical_align::baseline => (-ascent, false),
vertical_align::middle => {
// TODO: x-height value should be used from font info.
let xheight = Au(0);
let fragment_height = fragment.content_height();
let offset_top = -(xheight + fragment_height).scale_by(0.5);
*height_above_baseline = offset_top.scale_by(-1.0);
*depth_below_baseline = fragment_height - *height_above_baseline;
(offset_top, false)
// TODO: x-block-size value should be used from font info.
let xblock_size = Au(0);
let fragment_block_size = fragment.content_block_size();
let offset_block_start = -(xblock_size + fragment_block_size).scale_by(0.5);
*block_size_above_baseline = offset_block_start.scale_by(-1.0);
*depth_below_baseline = fragment_block_size - *block_size_above_baseline;
(offset_block_start, false)
},
vertical_align::sub => {
// TODO: The proper position for subscripts should be used. Lower the baseline to
@ -988,30 +998,30 @@ impl InlineFlow {
(-super_offset - ascent, false)
},
vertical_align::text_top => {
let fragment_height = *height_above_baseline + *depth_below_baseline;
let fragment_block_size = *block_size_above_baseline + *depth_below_baseline;
let prev_depth_below_baseline = *depth_below_baseline;
*height_above_baseline = parent_text_top;
*depth_below_baseline = fragment_height - *height_above_baseline;
*block_size_above_baseline = parent_text_block_start;
*depth_below_baseline = fragment_block_size - *block_size_above_baseline;
(*depth_below_baseline - prev_depth_below_baseline - ascent, false)
},
vertical_align::text_bottom => {
let fragment_height = *height_above_baseline + *depth_below_baseline;
let fragment_block_size = *block_size_above_baseline + *depth_below_baseline;
let prev_depth_below_baseline = *depth_below_baseline;
*depth_below_baseline = parent_text_bottom;
*height_above_baseline = fragment_height - *depth_below_baseline;
*depth_below_baseline = parent_text_block_end;
*block_size_above_baseline = fragment_block_size - *depth_below_baseline;
(*depth_below_baseline - prev_depth_below_baseline - ascent, false)
},
vertical_align::top => {
*largest_height_for_top_fragments =
Au::max(*largest_height_for_top_fragments,
*height_above_baseline + *depth_below_baseline);
let offset_top = *height_above_baseline - ascent;
*largest_block_size_for_top_fragments =
Au::max(*largest_block_size_for_top_fragments,
*block_size_above_baseline + *depth_below_baseline);
let offset_top = *block_size_above_baseline - ascent;
(offset_top, true)
},
vertical_align::bottom => {
*largest_height_for_bottom_fragments =
Au::max(*largest_height_for_bottom_fragments,
*height_above_baseline + *depth_below_baseline);
*largest_block_size_for_bottom_fragments =
Au::max(*largest_block_size_for_bottom_fragments,
*block_size_above_baseline + *depth_below_baseline);
let offset_bottom = -(*depth_below_baseline + ascent);
(offset_bottom, true)
},
@ -1029,26 +1039,28 @@ impl InlineFlow {
fn set_horizontal_fragment_positions(fragments: &mut InlineFragments,
line: &Line,
line_align: text_align::T) {
// Figure out how much width we have.
let slack_width = Au::max(Au(0), line.green_zone.width - line.bounds.size.width);
// Figure out how much inline-size we have.
let slack_inline_size = Au::max(Au(0), line.green_zone.inline - line.bounds.size.inline);
// Set the fragment x positions based on that alignment.
let mut offset_x = line.bounds.origin.x;
let mut offset_x = line.bounds.start.i;
offset_x = offset_x + match line_align {
// So sorry, but justified text is more complicated than shuffling line
// coordinates.
//
// TODO(burg, issue #213): Implement `text-align: justify`.
text_align::left | text_align::justify => Au(0),
text_align::center => slack_width.scale_by(0.5),
text_align::right => slack_width,
text_align::center => slack_inline_size.scale_by(0.5),
text_align::right => slack_inline_size,
};
for i in each_fragment_index(&line.range) {
let fragment = fragments.get_mut(i.to_uint());
let size = fragment.border_box.size;
fragment.border_box = Rect(Point2D(offset_x, fragment.border_box.origin.y), size);
offset_x = offset_x + size.width;
fragment.border_box = LogicalRect::new(
fragment.style.writing_mode, offset_x, fragment.border_box.start.b,
size.inline, size.block);
offset_x = offset_x + size.inline;
}
}
@ -1063,7 +1075,7 @@ impl InlineFlow {
let font_metrics = text::font_metrics_for_style(font_context, &font_style);
let line_height = text::line_height_from_style(style, style.get_font().font_size);
let inline_metrics = InlineMetrics::from_font_metrics(&font_metrics, line_height);
(inline_metrics.height_above_baseline, inline_metrics.depth_below_baseline)
(inline_metrics.block_size_above_baseline, inline_metrics.depth_below_baseline)
}
}
@ -1080,39 +1092,43 @@ impl Flow for InlineFlow {
self
}
fn bubble_widths(&mut self, _: &mut LayoutContext) {
fn bubble_inline_sizes(&mut self, _: &mut LayoutContext) {
let writing_mode = self.base.writing_mode;
for kid in self.base.child_iter() {
flow::mut_base(kid).floats = Floats::new();
flow::mut_base(kid).floats = Floats::new(writing_mode);
}
let mut intrinsic_widths = IntrinsicWidths::new();
let mut intrinsic_inline_sizes = IntrinsicISizes::new();
for (fragment, context) in self.fragments.mut_iter() {
debug!("Flow: measuring {}", *fragment);
let fragment_intrinsic_widths = fragment.intrinsic_widths(Some(context));
intrinsic_widths.minimum_width = geometry::max(intrinsic_widths.minimum_width,
fragment_intrinsic_widths.minimum_width);
intrinsic_widths.preferred_width = intrinsic_widths.preferred_width +
fragment_intrinsic_widths.preferred_width;
let fragment_intrinsic_inline_sizes =
fragment.intrinsic_inline_sizes(Some(context));
intrinsic_inline_sizes.minimum_inline_size = geometry::max(
intrinsic_inline_sizes.minimum_inline_size,
fragment_intrinsic_inline_sizes.minimum_inline_size);
intrinsic_inline_sizes.preferred_inline_size =
intrinsic_inline_sizes.preferred_inline_size +
fragment_intrinsic_inline_sizes.preferred_inline_size;
}
self.base.intrinsic_widths = intrinsic_widths;
self.base.intrinsic_inline_sizes = intrinsic_inline_sizes;
}
/// Recursively (top-down) determines the actual width of child contexts and fragments. When called
/// on this context, the context has had its width set by the parent context.
fn assign_widths(&mut self, _: &mut LayoutContext) {
// Initialize content fragment widths if they haven't been initialized already.
/// 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.
fn assign_inline_sizes(&mut self, _: &mut LayoutContext) {
// 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`.
debug!("InlineFlow::assign_widths: floats in: {:?}", self.base.floats);
debug!("InlineFlow::assign_inline_sizes: floats in: {:?}", self.base.floats);
{
let width = self.base.position.size.width;
let inline_size = self.base.position.size.inline;
let this = &mut *self;
for (fragment, context) in this.fragments.mut_iter() {
fragment.assign_replaced_width_if_necessary(width,
fragment.assign_replaced_inline_size_if_necessary(inline_size,
Some(context))
}
}
@ -1123,30 +1139,30 @@ impl Flow for InlineFlow {
// There are no child contexts, so stop here.
// TODO(Issue #225): once there are 'inline-block' elements, this won't be
// true. In that case, set the InlineBlockFragment's width to the
// shrink-to-fit width, perform inline flow, and set the block
// flow context's width as the assigned width of the
// true. In that case, set the InlineBlockFragment's inline-size to the
// shrink-to-fit inline-size, perform inline flow, and set the block
// flow context's inline-size as the assigned inline-size of the
// 'inline-block' fragment that created this flow before recursing.
}
/// Calculate and set the height of this flow. See CSS 2.1 § 10.6.1.
fn assign_height(&mut self, _: &mut LayoutContext) {
debug!("assign_height_inline: assigning height for flow");
/// Calculate and set the block-size of this flow. See CSS 2.1 § 10.6.1.
fn assign_block_size(&mut self, _: &mut LayoutContext) {
debug!("assign_block_size_inline: assigning block_size for flow");
// Divide the fragments into lines.
//
// TODO(#226): Get the CSS `line-height` property from the containing block's style to
// determine minimum line height.
// TODO(#226): Get the CSS `line-block-size` property from the containing block's style to
// determine minimum line block-size.
//
// TODO(#226): Get the CSS `line-height` property from each non-replaced inline element to
// determine its height for computing line height.
// TODO(#226): Get the CSS `line-block-size` property from each non-replaced inline element to
// determine its block-size for computing line block-size.
//
// TODO(pcwalton): Cache the line scanner?
debug!("assign_height_inline: floats in: {:?}", self.base.floats);
debug!("assign_block_size_inline: floats in: {:?}", self.base.floats);
// assign height for inline fragments
// assign block-size for inline fragments
for (fragment, _) in self.fragments.mut_iter() {
fragment.assign_replaced_height_if_necessary();
fragment.assign_replaced_block_size_if_necessary();
}
let scanner_floats = self.base.floats.clone();
@ -1157,29 +1173,29 @@ impl Flow for InlineFlow {
let text_align = self.base.flags.text_align();
// Now, go through each line and lay out the fragments inside.
let mut line_distance_from_flow_top = Au(0);
let mut line_distance_from_flow_block_start = Au(0);
for line in self.lines.mut_iter() {
// Lay out fragments horizontally.
InlineFlow::set_horizontal_fragment_positions(&mut self.fragments, line, text_align);
// Set the top y position of the current line.
// Set the block-start y position of the current line.
// `line_height_offset` is updated at the end of the previous loop.
line.bounds.origin.y = line_distance_from_flow_top;
line.bounds.start.b = line_distance_from_flow_block_start;
// Calculate the distance from the baseline to the top and bottom of the line.
let mut largest_height_above_baseline = self.minimum_height_above_baseline;
// Calculate the distance from the baseline to the block-start and block-end of the line.
let mut largest_block_size_above_baseline = self.minimum_block_size_above_baseline;
let mut largest_depth_below_baseline = self.minimum_depth_below_baseline;
// Calculate the largest height among fragments with 'top' and 'bottom' values
// Calculate the largest block-size among fragments with 'top' and 'bottom' values
// respectively.
let (mut largest_height_for_top_fragments, mut largest_height_for_bottom_fragments) =
let (mut largest_block_size_for_top_fragments, mut largest_block_size_for_bottom_fragments) =
(Au(0), Au(0));
for fragment_i in each_fragment_index(&line.range) {
let fragment = self.fragments.fragments.get_mut(fragment_i.to_uint());
let InlineMetrics {
height_above_baseline: mut height_above_baseline,
block_size_above_baseline: mut block_size_above_baseline,
depth_below_baseline: mut depth_below_baseline,
ascent
} = fragment.inline_metrics();
@ -1189,7 +1205,7 @@ impl Flow for InlineFlow {
// "Content area" is defined in CSS 2.1 § 10.6.1.
//
// TODO: We should extract em-box info from the font size of the parent and
// calculate the distances from the baseline to the top and the bottom of the
// calculate the distances from the baseline to the block-start and the block-end of the
// parent's content area.
// We should calculate the distance from baseline to the top of parent's content
@ -1203,10 +1219,10 @@ impl Flow for InlineFlow {
// content area. But for now we assume it's zero.
let parent_text_bottom = Au(0);
// Calculate the final height above the baseline for this fragment.
// Calculate the final block-size above the baseline for this fragment.
//
// The no-update flag decides whether `largest_height_for_top_fragments` and
// `largest_height_for_bottom_fragments` are to be updated or not. This will be set
// The no-update flag decides whether `largest_block-size_for_top_fragments` and
// `largest_block-size_for_bottom_fragments` are to be updated or not. This will be set
// if and only if the fragment has `vertical-align` set to `top` or `bottom`.
let (distance_from_baseline, no_update_flag) =
InlineFlow::distance_from_baseline(
@ -1214,77 +1230,78 @@ impl Flow for InlineFlow {
ascent,
parent_text_top,
parent_text_bottom,
&mut height_above_baseline,
&mut block_size_above_baseline,
&mut depth_below_baseline,
&mut largest_height_for_top_fragments,
&mut largest_height_for_bottom_fragments);
&mut largest_block_size_for_top_fragments,
&mut largest_block_size_for_bottom_fragments);
// Unless the current fragment has `vertical-align` set to `top` or `bottom`,
// `largest_height_above_baseline` and `largest_depth_below_baseline` are updated.
// `largest_block-size_above_baseline` and `largest_depth_below_baseline` are updated.
if !no_update_flag {
largest_height_above_baseline = Au::max(height_above_baseline,
largest_height_above_baseline);
largest_block_size_above_baseline = Au::max(block_size_above_baseline,
largest_block_size_above_baseline);
largest_depth_below_baseline = Au::max(depth_below_baseline,
largest_depth_below_baseline);
}
// Temporarily use `fragment.border_box.origin.y` to mean "the distance from the
// Temporarily use `fragment.border_box.start.b` to mean "the distance from the
// baseline". We will assign the real value later.
fragment.border_box.origin.y = distance_from_baseline
fragment.border_box.start.b = distance_from_baseline
}
// Calculate the distance from the baseline to the top of the largest fragment with a
// value for `bottom`. Then, if necessary, update `largest_height_above_baseline`.
largest_height_above_baseline =
Au::max(largest_height_above_baseline,
largest_height_for_bottom_fragments - largest_depth_below_baseline);
// value for `bottom`. Then, if necessary, update `largest_block-size_above_baseline`.
largest_block_size_above_baseline =
Au::max(largest_block_size_above_baseline,
largest_block_size_for_bottom_fragments - largest_depth_below_baseline);
// Calculate the distance from baseline to the bottom of the largest fragment with a value
// for `top`. Then, if necessary, update `largest_depth_below_baseline`.
largest_depth_below_baseline =
Au::max(largest_depth_below_baseline,
largest_height_for_top_fragments - largest_height_above_baseline);
largest_block_size_for_top_fragments - largest_block_size_above_baseline);
// Now, the distance from the logical top of the line to the baseline can be
// computed as `largest_height_above_baseline`.
let baseline_distance_from_top = largest_height_above_baseline;
// Now, the distance from the logical block-start of the line to the baseline can be
// computed as `largest_block-size_above_baseline`.
let baseline_distance_from_block_start = largest_block_size_above_baseline;
// Compute the final positions in the block direction of each fragment. Recall that
// `fragment.border_box.origin.y` was set to the distance from the baseline above.
// `fragment.border_box.start.b` was set to the distance from the baseline above.
for fragment_i in each_fragment_index(&line.range) {
let fragment = self.fragments.get_mut(fragment_i.to_uint());
match fragment.vertical_align() {
vertical_align::top => {
fragment.border_box.origin.y = fragment.border_box.origin.y +
line_distance_from_flow_top
fragment.border_box.start.b = fragment.border_box.start.b +
line_distance_from_flow_block_start
}
vertical_align::bottom => {
fragment.border_box.origin.y = fragment.border_box.origin.y +
line_distance_from_flow_top + baseline_distance_from_top +
fragment.border_box.start.b = fragment.border_box.start.b +
line_distance_from_flow_block_start + baseline_distance_from_block_start +
largest_depth_below_baseline
}
_ => {
fragment.border_box.origin.y = fragment.border_box.origin.y +
line_distance_from_flow_top + baseline_distance_from_top
fragment.border_box.start.b = fragment.border_box.start.b +
line_distance_from_flow_block_start + baseline_distance_from_block_start
}
}
}
// This is used to set the top y position of the next line in the next loop.
line.bounds.size.height = largest_height_above_baseline + largest_depth_below_baseline;
line_distance_from_flow_top = line_distance_from_flow_top + line.bounds.size.height;
// This is used to set the block-start y position of the next line in the next loop.
line.bounds.size.block = largest_block_size_above_baseline + largest_depth_below_baseline;
line_distance_from_flow_block_start = line_distance_from_flow_block_start + line.bounds.size.block;
} // End of `lines.each` loop.
self.base.position.size.height =
self.base.position.size.block =
if self.lines.len() > 0 {
self.lines.as_slice().last().get_ref().bounds.origin.y +
self.lines.as_slice().last().get_ref().bounds.size.height
self.lines.as_slice().last().get_ref().bounds.start.b +
self.lines.as_slice().last().get_ref().bounds.size.block
} else {
Au::new(0)
};
self.base.floats = scanner.floats();
self.base.floats.translate(Point2D(Au::new(0), -self.base.position.size.height));
self.base.floats.translate(LogicalSize::new(
self.base.writing_mode, Au::new(0), -self.base.position.size.block));
}
}
@ -1321,12 +1338,14 @@ impl InlineFragmentRange {
}
/// Returns the dimensions of the border in this fragment range.
pub fn border(&self) -> SideOffsets2D<Au> {
model::border_from_style(&*self.style)
#[inline]
pub fn border(&self) -> LogicalMargin<Au> {
self.style.logical_border_width()
}
/// Returns the dimensions of the padding in this fragment range.
pub fn padding(&self) -> SideOffsets2D<Au> {
#[inline]
pub fn padding(&self) -> LogicalMargin<Au> {
// FIXME(#2266, pcwalton): Is Au(0) right here for the containing block?
model::padding_from_style(&*self.style, Au(0))
}
@ -1400,21 +1419,21 @@ impl<'a> InlineFragmentContext<'a> {
}
}
/// Height above the baseline, depth below the baseline, and ascent for a fragment. See CSS 2.1 §
/// BSize above the baseline, depth below the baseline, and ascent for a fragment. See CSS 2.1 §
/// 10.8.1.
pub struct InlineMetrics {
pub height_above_baseline: Au,
pub block_size_above_baseline: Au,
pub depth_below_baseline: Au,
pub ascent: Au,
}
impl InlineMetrics {
/// Calculates inline metrics from font metrics and line height per CSS 2.1 § 10.8.1.
/// Calculates inline metrics from font metrics and line block-size per CSS 2.1 § 10.8.1.
#[inline]
pub fn from_font_metrics(font_metrics: &FontMetrics, line_height: Au) -> InlineMetrics {
let leading = line_height - (font_metrics.ascent + font_metrics.descent);
InlineMetrics {
height_above_baseline: font_metrics.ascent + leading.scale_by(0.5),
block_size_above_baseline: font_metrics.ascent + leading.scale_by(0.5),
depth_below_baseline: font_metrics.descent + leading.scale_by(0.5),
ascent: font_metrics.ascent,
}

Просмотреть файл

@ -171,16 +171,16 @@ impl PreorderFlowTraversal for FlowTreeVerificationTraversal {
}
}
/// The bubble-widths traversal, the first part of layout computation. This computes preferred
/// and intrinsic widths and bubbles them up the tree.
pub struct BubbleWidthsTraversal<'a> {
/// The bubble-inline-sizes traversal, the first part of layout computation. This computes preferred
/// and intrinsic inline-sizes and bubbles them up the tree.
pub struct BubbleISizesTraversal<'a> {
pub layout_context: &'a mut LayoutContext,
}
impl<'a> PostorderFlowTraversal for BubbleWidthsTraversal<'a> {
impl<'a> PostorderFlowTraversal for BubbleISizesTraversal<'a> {
#[inline]
fn process(&mut self, flow: &mut Flow) -> bool {
flow.bubble_widths(self.layout_context);
flow.bubble_inline_sizes(self.layout_context);
true
}
@ -188,35 +188,35 @@ impl<'a> PostorderFlowTraversal for BubbleWidthsTraversal<'a> {
/*
#[inline]
fn should_prune(&mut self, flow: &mut Flow) -> bool {
flow::mut_base(flow).restyle_damage.lacks(BubbleWidths)
flow::mut_base(flow).restyle_damage.lacks(BubbleISizes)
}
*/
}
/// The assign-widths traversal. In Gecko this corresponds to `Reflow`.
pub struct AssignWidthsTraversal<'a> {
/// The assign-inline-sizes traversal. In Gecko this corresponds to `Reflow`.
pub struct AssignISizesTraversal<'a> {
pub layout_context: &'a mut LayoutContext,
}
impl<'a> PreorderFlowTraversal for AssignWidthsTraversal<'a> {
impl<'a> PreorderFlowTraversal for AssignISizesTraversal<'a> {
#[inline]
fn process(&mut self, flow: &mut Flow) -> bool {
flow.assign_widths(self.layout_context);
flow.assign_inline_sizes(self.layout_context);
true
}
}
/// The assign-heights-and-store-overflow traversal, the last (and most expensive) part of layout
/// computation. Determines the final heights for all layout objects, computes positions, and
/// The assign-block-sizes-and-store-overflow traversal, the last (and most expensive) part of layout
/// computation. Determines the final block-sizes for all layout objects, computes positions, and
/// computes overflow regions. In Gecko this corresponds to `FinishAndStoreOverflow`.
pub struct AssignHeightsAndStoreOverflowTraversal<'a> {
pub struct AssignBSizesAndStoreOverflowTraversal<'a> {
pub layout_context: &'a mut LayoutContext,
}
impl<'a> PostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> {
impl<'a> PostorderFlowTraversal for AssignBSizesAndStoreOverflowTraversal<'a> {
#[inline]
fn process(&mut self, flow: &mut Flow) -> bool {
flow.assign_height(self.layout_context);
flow.assign_block_size(self.layout_context);
// Skip store-overflow for absolutely positioned flows. That will be
// done in a separate traversal.
if !flow.is_store_overflow_delayed() {
@ -482,8 +482,8 @@ impl LayoutTask {
fn solve_constraints(&mut self,
layout_root: &mut Flow,
layout_context: &mut LayoutContext) {
if layout_context.opts.bubble_widths_separately {
let mut traversal = BubbleWidthsTraversal {
if layout_context.opts.bubble_inline_sizes_separately {
let mut traversal = BubbleISizesTraversal {
layout_context: layout_context,
};
layout_root.traverse_postorder(&mut traversal);
@ -495,7 +495,7 @@ impl LayoutTask {
// NOTE: this currently computes borders, so any pruning should separate that operation
// out.
{
let mut traversal = AssignWidthsTraversal {
let mut traversal = AssignISizesTraversal {
layout_context: layout_context,
};
layout_root.traverse_preorder(&mut traversal);
@ -503,7 +503,7 @@ impl LayoutTask {
// FIXME(pcwalton): Prune this pass as well.
{
let mut traversal = AssignHeightsAndStoreOverflowTraversal {
let mut traversal = AssignBSizesAndStoreOverflowTraversal {
layout_context: layout_context,
};
layout_root.traverse_postorder(&mut traversal);
@ -518,8 +518,8 @@ impl LayoutTask {
fn solve_constraints_parallel(&mut self,
layout_root: &mut FlowRef,
layout_context: &mut LayoutContext) {
if layout_context.opts.bubble_widths_separately {
let mut traversal = BubbleWidthsTraversal {
if layout_context.opts.bubble_inline_sizes_separately {
let mut traversal = BubbleISizesTraversal {
layout_context: layout_context,
};
layout_root.get_mut().traverse_postorder(&mut traversal);
@ -656,8 +656,12 @@ impl LayoutTask {
// Build the display list if necessary, and send it to the renderer.
if data.goal == ReflowForDisplay {
let writing_mode = flow::base(layout_root.get()).writing_mode;
profile(time::LayoutDispListBuildCategory, self.time_profiler_chan.clone(), || {
layout_ctx.dirty = flow::base(layout_root.get()).position.clone();
// FIXME(#2795): Get the real container size
let container_size = Size2D::zero();
layout_ctx.dirty = flow::base(layout_root.get()).position.to_physical(
writing_mode, container_size);
match self.parallel_traversal {
None => {
@ -703,7 +707,10 @@ impl LayoutTask {
}
}
let root_size = flow::base(layout_root.get()).position.size;
let root_size = {
let root_flow = flow::base(layout_root.get());
root_flow.position.size.to_physical(root_flow.writing_mode)
};
let root_size = Size2D(root_size.width.to_nearest_px() as uint,
root_size.height.to_nearest_px() as uint);
let render_layer = RenderLayer {

Просмотреть файл

@ -14,6 +14,7 @@ use style::computed_values::{LPA_Auto, LPA_Length, LPA_Percentage, LP_Length, LP
use style::ComputedValues;
use servo_util::geometry::Au;
use servo_util::geometry;
use servo_util::logical_geometry::LogicalMargin;
use std::fmt;
/// A collapsible margin. See CSS 2.1 § 8.3.1.
@ -58,12 +59,12 @@ impl AdjoiningMargins {
}
}
/// Represents the top and bottom margins of a flow with collapsible margins. See CSS 2.1 § 8.3.1.
/// Represents the block-start and block-end margins of a flow with collapsible margins. See CSS 2.1 § 8.3.1.
pub enum CollapsibleMargins {
/// Margins may not collapse with this flow.
NoCollapsibleMargins(Au, Au),
/// Both the top and bottom margins (specified here in that order) may collapse, but the
/// Both the block-start and block-end margins (specified here in that order) may collapse, but the
/// margins do not collapse through this flow.
MarginsCollapse(AdjoiningMargins, AdjoiningMargins),
@ -85,7 +86,7 @@ enum FinalMarginState {
pub struct MarginCollapseInfo {
pub state: MarginCollapseState,
pub top_margin: AdjoiningMargins,
pub block_start_margin: AdjoiningMargins,
pub margin_in: AdjoiningMargins,
}
@ -94,42 +95,42 @@ impl MarginCollapseInfo {
pub fn new() -> MarginCollapseInfo {
MarginCollapseInfo {
state: AccumulatingCollapsibleTopMargin,
top_margin: AdjoiningMargins::new(),
block_start_margin: AdjoiningMargins::new(),
margin_in: AdjoiningMargins::new(),
}
}
pub fn initialize_top_margin(&mut self,
pub fn initialize_block_start_margin(&mut self,
fragment: &Fragment,
can_collapse_top_margin_with_kids: bool) {
if !can_collapse_top_margin_with_kids {
can_collapse_block_start_margin_with_kids: bool) {
if !can_collapse_block_start_margin_with_kids {
self.state = AccumulatingMarginIn
}
self.top_margin = AdjoiningMargins::from_margin(fragment.margin.top)
self.block_start_margin = AdjoiningMargins::from_margin(fragment.margin.block_start)
}
pub fn finish_and_compute_collapsible_margins(mut self,
fragment: &Fragment,
can_collapse_bottom_margin_with_kids: bool)
can_collapse_block_end_margin_with_kids: bool)
-> (CollapsibleMargins, Au) {
let state = match self.state {
AccumulatingCollapsibleTopMargin => {
match fragment.style().get_box().height {
match fragment.style().content_block_size() {
LPA_Auto | LPA_Length(Au(0)) | LPA_Percentage(0.) => {
match fragment.style().get_box().min_height {
match fragment.style().min_block_size() {
LP_Length(Au(0)) | LP_Percentage(0.) => {
MarginsCollapseThroughFinalMarginState
},
_ => {
// If the fragment has non-zero min-height, margins may not
// If the fragment has non-zero min-block-size, margins may not
// collapse through it.
BottomMarginCollapsesFinalMarginState
}
}
},
_ => {
// If the fragment has an explicitly specified height, margins may not
// If the fragment has an explicitly specified block-size, margins may not
// collapse through it.
BottomMarginCollapsesFinalMarginState
}
@ -138,31 +139,31 @@ impl MarginCollapseInfo {
AccumulatingMarginIn => BottomMarginCollapsesFinalMarginState,
};
// Different logic is needed here depending on whether this flow can collapse its bottom
// Different logic is needed here depending on whether this flow can collapse its block-end
// margin with its children.
let bottom_margin = fragment.margin.bottom;
if !can_collapse_bottom_margin_with_kids {
let block_end_margin = fragment.margin.block_end;
if !can_collapse_block_end_margin_with_kids {
match state {
MarginsCollapseThroughFinalMarginState => {
let advance = self.top_margin.collapse();
self.margin_in.union(AdjoiningMargins::from_margin(bottom_margin));
(MarginsCollapse(self.top_margin, self.margin_in), advance)
let advance = self.block_start_margin.collapse();
self.margin_in.union(AdjoiningMargins::from_margin(block_end_margin));
(MarginsCollapse(self.block_start_margin, self.margin_in), advance)
}
BottomMarginCollapsesFinalMarginState => {
let advance = self.margin_in.collapse();
self.margin_in.union(AdjoiningMargins::from_margin(bottom_margin));
(MarginsCollapse(self.top_margin, self.margin_in), advance)
self.margin_in.union(AdjoiningMargins::from_margin(block_end_margin));
(MarginsCollapse(self.block_start_margin, self.margin_in), advance)
}
}
} else {
match state {
MarginsCollapseThroughFinalMarginState => {
self.top_margin.union(AdjoiningMargins::from_margin(bottom_margin));
(MarginsCollapseThrough(self.top_margin), Au(0))
self.block_start_margin.union(AdjoiningMargins::from_margin(block_end_margin));
(MarginsCollapseThrough(self.block_start_margin), Au(0))
}
BottomMarginCollapsesFinalMarginState => {
self.margin_in.union(AdjoiningMargins::from_margin(bottom_margin));
(MarginsCollapse(self.top_margin, self.margin_in), Au(0))
self.margin_in.union(AdjoiningMargins::from_margin(block_end_margin));
(MarginsCollapse(self.block_start_margin, self.margin_in), Au(0))
}
}
}
@ -170,66 +171,66 @@ impl MarginCollapseInfo {
pub fn current_float_ceiling(&mut self) -> Au {
match self.state {
AccumulatingCollapsibleTopMargin => self.top_margin.collapse(),
AccumulatingCollapsibleTopMargin => self.block_start_margin.collapse(),
AccumulatingMarginIn => self.margin_in.collapse(),
}
}
/// Adds the child's potentially collapsible top margin to the current margin state and
/// Adds the child's potentially collapsible block-start margin to the current margin state and
/// advances the Y offset by the appropriate amount to handle that margin. Returns the amount
/// that should be added to the Y offset during block layout.
pub fn advance_top_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) -> Au {
pub fn advance_block_start_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) -> Au {
match (self.state, *child_collapsible_margins) {
(AccumulatingCollapsibleTopMargin, NoCollapsibleMargins(top, _)) => {
(AccumulatingCollapsibleTopMargin, NoCollapsibleMargins(block_start, _)) => {
self.state = AccumulatingMarginIn;
top
block_start
}
(AccumulatingCollapsibleTopMargin, MarginsCollapse(top, _)) => {
self.top_margin.union(top);
(AccumulatingCollapsibleTopMargin, MarginsCollapse(block_start, _)) => {
self.block_start_margin.union(block_start);
self.state = AccumulatingMarginIn;
Au(0)
}
(AccumulatingMarginIn, NoCollapsibleMargins(top, _)) => {
(AccumulatingMarginIn, NoCollapsibleMargins(block_start, _)) => {
let previous_margin_value = self.margin_in.collapse();
self.margin_in = AdjoiningMargins::new();
previous_margin_value + top
previous_margin_value + block_start
}
(AccumulatingMarginIn, MarginsCollapse(top, _)) => {
self.margin_in.union(top);
(AccumulatingMarginIn, MarginsCollapse(block_start, _)) => {
self.margin_in.union(block_start);
let margin_value = self.margin_in.collapse();
self.margin_in = AdjoiningMargins::new();
margin_value
}
(_, MarginsCollapseThrough(_)) => {
// For now, we ignore this; this will be handled by `advance_bottom_margin` below.
// For now, we ignore this; this will be handled by `advance_block-end_margin` below.
Au(0)
}
}
}
/// Adds the child's potentially collapsible bottom margin to the current margin state and
/// Adds the child's potentially collapsible block-end margin to the current margin state and
/// advances the Y offset by the appropriate amount to handle that margin. Returns the amount
/// that should be added to the Y offset during block layout.
pub fn advance_bottom_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) -> Au {
pub fn advance_block_end_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) -> Au {
match (self.state, *child_collapsible_margins) {
(AccumulatingCollapsibleTopMargin, NoCollapsibleMargins(..)) |
(AccumulatingCollapsibleTopMargin, MarginsCollapse(..)) => {
// Can't happen because the state will have been replaced with
// `AccumulatingMarginIn` above.
fail!("should not be accumulating collapsible top margins anymore!")
fail!("should not be accumulating collapsible block_start margins anymore!")
}
(AccumulatingCollapsibleTopMargin, MarginsCollapseThrough(margin)) => {
self.top_margin.union(margin);
self.block_start_margin.union(margin);
Au(0)
}
(AccumulatingMarginIn, NoCollapsibleMargins(_, bottom)) => {
(AccumulatingMarginIn, NoCollapsibleMargins(_, block_end)) => {
assert_eq!(self.margin_in.most_positive, Au(0));
assert_eq!(self.margin_in.most_negative, Au(0));
bottom
block_end
}
(AccumulatingMarginIn, MarginsCollapse(_, bottom)) |
(AccumulatingMarginIn, MarginsCollapseThrough(bottom)) => {
self.margin_in.union(bottom);
(AccumulatingMarginIn, MarginsCollapse(_, block_end)) |
(AccumulatingMarginIn, MarginsCollapseThrough(block_end)) => {
self.margin_in.union(block_end);
Au(0)
}
}
@ -241,38 +242,38 @@ pub enum MarginCollapseState {
AccumulatingMarginIn,
}
/// Intrinsic widths, which consist of minimum and preferred.
pub struct IntrinsicWidths {
/// The *minimum width* of the content.
pub minimum_width: Au,
/// The *preferred width* of the content.
pub preferred_width: Au,
/// Intrinsic inline-sizes, which consist of minimum and preferred.
pub struct IntrinsicISizes {
/// The *minimum inline-size* of the content.
pub minimum_inline_size: Au,
/// The *preferred inline-size* of the content.
pub preferred_inline_size: Au,
/// The estimated sum of borders, padding, and margins. Some calculations use this information
/// when computing intrinsic widths.
pub surround_width: Au,
/// when computing intrinsic inline-sizes.
pub surround_inline_size: Au,
}
impl fmt::Show for IntrinsicWidths {
impl fmt::Show for IntrinsicISizes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "min={}, pref={}, surr={}", self.minimum_width, self.preferred_width, self.surround_width)
write!(f, "min={}, pref={}, surr={}", self.minimum_inline_size, self.preferred_inline_size, self.surround_inline_size)
}
}
impl IntrinsicWidths {
pub fn new() -> IntrinsicWidths {
IntrinsicWidths {
minimum_width: Au(0),
preferred_width: Au(0),
surround_width: Au(0),
impl IntrinsicISizes {
pub fn new() -> IntrinsicISizes {
IntrinsicISizes {
minimum_inline_size: Au(0),
preferred_inline_size: Au(0),
surround_inline_size: Au(0),
}
}
pub fn total_minimum_width(&self) -> Au {
self.minimum_width + self.surround_width
pub fn total_minimum_inline_size(&self) -> Au {
self.minimum_inline_size + self.surround_inline_size
}
pub fn total_preferred_width(&self) -> Au {
self.preferred_width + self.surround_width
pub fn total_preferred_inline_size(&self) -> Au {
self.preferred_inline_size + self.surround_inline_size
}
}
@ -323,21 +324,13 @@ pub fn specified(length: computed::LengthOrPercentage, containing_length: Au) ->
}
#[inline]
pub fn border_from_style(style: &ComputedValues) -> SideOffsets2D<Au> {
let border_style = style.get_border();
SideOffsets2D::new(border_style.border_top_width,
border_style.border_right_width,
border_style.border_bottom_width,
border_style.border_left_width)
}
#[inline]
pub fn padding_from_style(style: &ComputedValues, containing_block_width: Au)
-> SideOffsets2D<Au> {
pub fn padding_from_style(style: &ComputedValues, containing_block_inline_size: Au)
-> LogicalMargin<Au> {
let padding_style = style.get_padding();
SideOffsets2D::new(specified(padding_style.padding_top, containing_block_width),
specified(padding_style.padding_right, containing_block_width),
specified(padding_style.padding_bottom, containing_block_width),
specified(padding_style.padding_left, containing_block_width))
LogicalMargin::from_physical(style.writing_mode, SideOffsets2D::new(
specified(padding_style.padding_top, containing_block_inline_size),
specified(padding_style.padding_right, containing_block_inline_size),
specified(padding_style.padding_bottom, containing_block_inline_size),
specified(padding_style.padding_left, containing_block_inline_size)))
}

Просмотреть файл

@ -13,8 +13,8 @@ use extra::LayoutAuxMethods;
use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal};
use flow;
use flow_ref::FlowRef;
use layout_task::{AssignHeightsAndStoreOverflowTraversal, AssignWidthsTraversal};
use layout_task::{BubbleWidthsTraversal};
use layout_task::{AssignBSizesAndStoreOverflowTraversal, AssignISizesTraversal};
use layout_task::{BubbleISizesTraversal};
use util::{LayoutDataAccess, LayoutDataWrapper, OpaqueNodeMethods};
use wrapper::{layout_node_to_unsafe_layout_node, layout_node_from_unsafe_layout_node, LayoutNode, PostorderNodeMutTraversal};
use wrapper::{ThreadSafeLayoutNode, UnsafeLayoutNode};
@ -191,27 +191,27 @@ trait ParallelPreorderFlowTraversal : PreorderFlowTraversal {
}
// If there were no more children, start assigning heights.
// If there were no more children, start assigning block-sizes.
if !had_children {
bottom_up_func(unsafe_flow, proxy)
}
}
}
impl<'a> ParallelPostorderFlowTraversal for BubbleWidthsTraversal<'a> {}
impl<'a> ParallelPostorderFlowTraversal for BubbleISizesTraversal<'a> {}
impl<'a> ParallelPreorderFlowTraversal for AssignWidthsTraversal<'a> {
impl<'a> ParallelPreorderFlowTraversal for AssignISizesTraversal<'a> {
fn run_parallel(&mut self,
unsafe_flow: UnsafeFlow,
proxy: &mut WorkerProxy<*mut LayoutContext,UnsafeFlow>) {
self.run_parallel_helper(unsafe_flow,
proxy,
assign_widths,
assign_heights_and_store_overflow)
assign_inline_sizes,
assign_block_sizes_and_store_overflow)
}
}
impl<'a> ParallelPostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> {}
impl<'a> ParallelPostorderFlowTraversal for AssignBSizesAndStoreOverflowTraversal<'a> {}
fn recalc_style_for_node(unsafe_layout_node: UnsafeLayoutNode,
proxy: &mut WorkerProxy<*mut LayoutContext,UnsafeLayoutNode>) {
@ -371,22 +371,22 @@ fn construct_flows(mut unsafe_layout_node: UnsafeLayoutNode,
}
}
fn assign_widths(unsafe_flow: UnsafeFlow,
fn assign_inline_sizes(unsafe_flow: UnsafeFlow,
proxy: &mut WorkerProxy<*mut LayoutContext,UnsafeFlow>) {
let layout_context = unsafe { &mut **proxy.user_data() };
let mut assign_widths_traversal = AssignWidthsTraversal {
let mut assign_inline_sizes_traversal = AssignISizesTraversal {
layout_context: layout_context,
};
assign_widths_traversal.run_parallel(unsafe_flow, proxy)
assign_inline_sizes_traversal.run_parallel(unsafe_flow, proxy)
}
fn assign_heights_and_store_overflow(unsafe_flow: UnsafeFlow,
fn assign_block_sizes_and_store_overflow(unsafe_flow: UnsafeFlow,
proxy: &mut WorkerProxy<*mut LayoutContext,UnsafeFlow>) {
let layout_context = unsafe { &mut **proxy.user_data() };
let mut assign_heights_traversal = AssignHeightsAndStoreOverflowTraversal {
let mut assign_block_sizes_traversal = AssignBSizesAndStoreOverflowTraversal {
layout_context: layout_context,
};
assign_heights_traversal.run_parallel(unsafe_flow, proxy)
assign_block_sizes_traversal.run_parallel(unsafe_flow, proxy)
}
fn compute_absolute_position(unsafe_flow: UnsafeFlow,
@ -525,7 +525,7 @@ pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
profile(time::LayoutParallelWarmupCategory, time_profiler_chan, || {
queue.push(WorkUnit {
fun: assign_widths,
fun: assign_inline_sizes,
data: mut_owned_flow_to_unsafe_flow(root),
})
});

Просмотреть файл

@ -6,8 +6,8 @@
#![deny(unsafe_block)]
use block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer};
use block::{WidthConstraintInput, WidthConstraintSolution};
use block::{BlockFlow, MarginsMayNotCollapse, ISizeAndMarginsComputer};
use block::{ISizeConstraintInput, ISizeConstraintSolution};
use construct::FlowConstructor;
use context::LayoutContext;
use floats::FloatKind;
@ -27,14 +27,14 @@ use style::computed_values::table_layout;
pub struct TableFlow {
pub block_flow: BlockFlow,
/// Column widths
pub col_widths: Vec<Au>,
/// Column inline-sizes
pub col_inline_sizes: Vec<Au>,
/// Column min widths.
pub col_min_widths: Vec<Au>,
/// Column min inline-sizes.
pub col_min_inline_sizes: Vec<Au>,
/// Column pref widths.
pub col_pref_widths: Vec<Au>,
/// Column pref inline-sizes.
pub col_pref_inline_sizes: Vec<Au>,
/// Table-layout property
pub table_layout: TableLayout,
@ -53,9 +53,9 @@ impl TableFlow {
};
TableFlow {
block_flow: block_flow,
col_widths: vec!(),
col_min_widths: vec!(),
col_pref_widths: vec!(),
col_inline_sizes: vec!(),
col_min_inline_sizes: vec!(),
col_pref_inline_sizes: vec!(),
table_layout: table_layout
}
}
@ -72,9 +72,9 @@ impl TableFlow {
};
TableFlow {
block_flow: block_flow,
col_widths: vec!(),
col_min_widths: vec!(),
col_pref_widths: vec!(),
col_inline_sizes: vec!(),
col_min_inline_sizes: vec!(),
col_pref_inline_sizes: vec!(),
table_layout: table_layout
}
}
@ -92,41 +92,41 @@ impl TableFlow {
};
TableFlow {
block_flow: block_flow,
col_widths: vec!(),
col_min_widths: vec!(),
col_pref_widths: vec!(),
col_inline_sizes: vec!(),
col_min_inline_sizes: vec!(),
col_pref_inline_sizes: vec!(),
table_layout: table_layout
}
}
/// Update the corresponding value of self_widths if a value of kid_widths has larger value
/// than one of self_widths.
pub fn update_col_widths(self_widths: &mut Vec<Au>, kid_widths: &Vec<Au>) -> Au {
let mut sum_widths = Au(0);
let mut kid_widths_it = kid_widths.iter();
for self_width in self_widths.mut_iter() {
match kid_widths_it.next() {
Some(kid_width) => {
if *self_width < *kid_width {
*self_width = *kid_width;
/// Update the corresponding value of self_inline-sizes if a value of kid_inline-sizes has larger value
/// than one of self_inline-sizes.
pub fn update_col_inline_sizes(self_inline_sizes: &mut Vec<Au>, kid_inline_sizes: &Vec<Au>) -> Au {
let mut sum_inline_sizes = Au(0);
let mut kid_inline_sizes_it = kid_inline_sizes.iter();
for self_inline_size in self_inline_sizes.mut_iter() {
match kid_inline_sizes_it.next() {
Some(kid_inline_size) => {
if *self_inline_size < *kid_inline_size {
*self_inline_size = *kid_inline_size;
}
},
None => {}
}
sum_widths = sum_widths + *self_width;
sum_inline_sizes = sum_inline_sizes + *self_inline_size;
}
sum_widths
sum_inline_sizes
}
/// Assign height for table flow.
/// Assign block-size for table flow.
///
/// TODO(#2014, pcwalton): This probably doesn't handle margin collapse right.
///
/// inline(always) because this is only ever called by in-order or non-in-order top-level
/// methods
#[inline(always)]
fn assign_height_table_base(&mut self, layout_context: &mut LayoutContext) {
self.block_flow.assign_height_block_base(layout_context, MarginsMayNotCollapse);
fn assign_block_size_table_base(&mut self, layout_context: &mut LayoutContext) {
self.block_flow.assign_block_size_block_base(layout_context, MarginsMayNotCollapse);
}
pub fn build_display_list_table(&mut self, layout_context: &LayoutContext) {
@ -148,130 +148,130 @@ impl Flow for TableFlow {
&mut self.block_flow
}
fn col_widths<'a>(&'a mut self) -> &'a mut Vec<Au> {
&mut self.col_widths
fn col_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<Au> {
&mut self.col_inline_sizes
}
fn col_min_widths<'a>(&'a self) -> &'a Vec<Au> {
&self.col_min_widths
fn col_min_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
&self.col_min_inline_sizes
}
fn col_pref_widths<'a>(&'a self) -> &'a Vec<Au> {
&self.col_pref_widths
fn col_pref_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
&self.col_pref_inline_sizes
}
/// The specified column widths are set from column group and the first row for the fixed
/// The specified column inline-sizes are set from column group and the first row for the fixed
/// table layout calculation.
/// The maximum min/pref widths of each column are set from the rows for the automatic
/// The maximum min/pref inline-sizes of each column are set from the rows for the automatic
/// table layout calculation.
fn bubble_widths(&mut self, _: &mut LayoutContext) {
let mut min_width = Au(0);
let mut pref_width = Au(0);
fn bubble_inline_sizes(&mut self, _: &mut LayoutContext) {
let mut min_inline_size = Au(0);
let mut pref_inline_size = Au(0);
let mut did_first_row = false;
for kid in self.block_flow.base.child_iter() {
assert!(kid.is_proper_table_child());
if kid.is_table_colgroup() {
self.col_widths.push_all(kid.as_table_colgroup().widths.as_slice());
self.col_min_widths = self.col_widths.clone();
self.col_pref_widths = self.col_widths.clone();
self.col_inline_sizes.push_all(kid.as_table_colgroup().inline_sizes.as_slice());
self.col_min_inline_sizes = self.col_inline_sizes.clone();
self.col_pref_inline_sizes = self.col_inline_sizes.clone();
} else if kid.is_table_rowgroup() || kid.is_table_row() {
// read column widths from table-row-group/table-row, and assign
// width=0 for the columns not defined in column-group
// FIXME: need to read widths from either table-header-group OR
// read column inline-sizes from table-row-group/table-row, and assign
// inline-size=0 for the columns not defined in column-group
// FIXME: need to read inline-sizes from either table-header-group OR
// first table-row
match self.table_layout {
FixedLayout => {
let kid_col_widths = kid.col_widths();
let kid_col_inline_sizes = kid.col_inline_sizes();
if !did_first_row {
did_first_row = true;
let mut child_widths = kid_col_widths.iter();
for col_width in self.col_widths.mut_iter() {
match child_widths.next() {
Some(child_width) => {
if *col_width == Au::new(0) {
*col_width = *child_width;
let mut child_inline_sizes = kid_col_inline_sizes.iter();
for col_inline_size in self.col_inline_sizes.mut_iter() {
match child_inline_sizes.next() {
Some(child_inline_size) => {
if *col_inline_size == Au::new(0) {
*col_inline_size = *child_inline_size;
}
},
None => break
}
}
}
let num_child_cols = kid_col_widths.len();
let num_cols = self.col_widths.len();
let num_child_cols = kid_col_inline_sizes.len();
let num_cols = self.col_inline_sizes.len();
debug!("table until the previous row has {} column(s) and this row has {} column(s)",
num_cols, num_child_cols);
for i in range(num_cols, num_child_cols) {
self.col_widths.push( *kid_col_widths.get(i) );
self.col_inline_sizes.push( *kid_col_inline_sizes.get(i) );
}
},
AutoLayout => {
min_width = TableFlow::update_col_widths(&mut self.col_min_widths, kid.col_min_widths());
pref_width = TableFlow::update_col_widths(&mut self.col_pref_widths, kid.col_pref_widths());
min_inline_size = TableFlow::update_col_inline_sizes(&mut self.col_min_inline_sizes, kid.col_min_inline_sizes());
pref_inline_size = TableFlow::update_col_inline_sizes(&mut self.col_pref_inline_sizes, kid.col_pref_inline_sizes());
// update the number of column widths from table-rows.
let num_cols = self.col_min_widths.len();
let num_child_cols = kid.col_min_widths().len();
// update the number of column inline-sizes from table-rows.
let num_cols = self.col_min_inline_sizes.len();
let num_child_cols = kid.col_min_inline_sizes().len();
debug!("table until the previous row has {} column(s) and this row has {} column(s)",
num_cols, num_child_cols);
for i in range(num_cols, num_child_cols) {
self.col_widths.push(Au::new(0));
let new_kid_min = *kid.col_min_widths().get(i);
self.col_min_widths.push( new_kid_min );
let new_kid_pref = *kid.col_pref_widths().get(i);
self.col_pref_widths.push( new_kid_pref );
min_width = min_width + new_kid_min;
pref_width = pref_width + new_kid_pref;
self.col_inline_sizes.push(Au::new(0));
let new_kid_min = *kid.col_min_inline_sizes().get(i);
self.col_min_inline_sizes.push( new_kid_min );
let new_kid_pref = *kid.col_pref_inline_sizes().get(i);
self.col_pref_inline_sizes.push( new_kid_pref );
min_inline_size = min_inline_size + new_kid_min;
pref_inline_size = pref_inline_size + new_kid_pref;
}
}
}
}
}
self.block_flow.base.intrinsic_widths.minimum_width = min_width;
self.block_flow.base.intrinsic_widths.preferred_width =
geometry::max(min_width, pref_width);
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = min_inline_size;
self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size =
geometry::max(min_inline_size, pref_inline_size);
}
/// Recursively (top-down) determines the actual width of child contexts and fragments. When
/// called on this context, the context has had its width set by the parent context.
fn assign_widths(&mut self, ctx: &mut LayoutContext) {
debug!("assign_widths({}): assigning width for flow", "table");
/// 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.
fn assign_inline_sizes(&mut self, ctx: &mut LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table");
// The position was set to the containing block by the flow's parent.
let containing_block_width = self.block_flow.base.position.size.width;
let containing_block_inline_size = self.block_flow.base.position.size.inline;
let mut num_unspecified_widths = 0;
let mut total_column_width = Au::new(0);
for col_width in self.col_widths.iter() {
if *col_width == Au::new(0) {
num_unspecified_widths += 1;
let mut num_unspecified_inline_sizes = 0;
let mut total_column_inline_size = Au::new(0);
for col_inline_size in self.col_inline_sizes.iter() {
if *col_inline_size == Au::new(0) {
num_unspecified_inline_sizes += 1;
} else {
total_column_width = total_column_width.add(col_width);
total_column_inline_size = total_column_inline_size.add(col_inline_size);
}
}
let width_computer = InternalTable;
width_computer.compute_used_width(&mut self.block_flow, ctx, containing_block_width);
let inline_size_computer = InternalTable;
inline_size_computer.compute_used_inline_size(&mut self.block_flow, ctx, containing_block_inline_size);
let left_content_edge = self.block_flow.fragment.border_padding.left;
let padding_and_borders = self.block_flow.fragment.border_padding.horizontal();
let content_width = self.block_flow.fragment.border_box.size.width - padding_and_borders;
let inline_start_content_edge = self.block_flow.fragment.border_padding.inline_start;
let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end();
let content_inline_size = self.block_flow.fragment.border_box.size.inline - padding_and_borders;
match self.table_layout {
FixedLayout => {
// In fixed table layout, we distribute extra space among the unspecified columns if there are
// any, or among all the columns if all are specified.
if (total_column_width < content_width) && (num_unspecified_widths == 0) {
let ratio = content_width.to_f64().unwrap() / total_column_width.to_f64().unwrap();
for col_width in self.col_widths.mut_iter() {
*col_width = (*col_width).scale_by(ratio);
if (total_column_inline_size < content_inline_size) && (num_unspecified_inline_sizes == 0) {
let ratio = content_inline_size.to_f64().unwrap() / total_column_inline_size.to_f64().unwrap();
for col_inline_size in self.col_inline_sizes.mut_iter() {
*col_inline_size = (*col_inline_size).scale_by(ratio);
}
} else if num_unspecified_widths != 0 {
let extra_column_width = (content_width - total_column_width) / Au::new(num_unspecified_widths);
for col_width in self.col_widths.mut_iter() {
if *col_width == Au(0) {
*col_width = extra_column_width;
} else if num_unspecified_inline_sizes != 0 {
let extra_column_inline_size = (content_inline_size - total_column_inline_size) / Au::new(num_unspecified_inline_sizes);
for col_inline_size in self.col_inline_sizes.mut_iter() {
if *col_inline_size == Au(0) {
*col_inline_size = extra_column_inline_size;
}
}
}
@ -279,12 +279,12 @@ impl Flow for TableFlow {
_ => {}
}
self.block_flow.propagate_assigned_width_to_children(left_content_edge, content_width, Some(self.col_widths.clone()));
self.block_flow.propagate_assigned_inline_size_to_children(inline_start_content_edge, content_inline_size, Some(self.col_inline_sizes.clone()));
}
fn assign_height(&mut self, ctx: &mut LayoutContext) {
debug!("assign_height: assigning height for table");
self.assign_height_table_base(ctx);
fn assign_block_size(&mut self, ctx: &mut LayoutContext) {
debug!("assign_block_size: assigning block_size for table");
self.assign_block_size_table_base(ctx);
}
fn compute_absolute_position(&mut self) {
@ -300,25 +300,25 @@ impl fmt::Show for TableFlow {
}
/// Table, TableRowGroup, TableRow, TableCell types.
/// Their widths are calculated in the same way and do not have margins.
/// Their inline-sizes are calculated in the same way and do not have margins.
pub struct InternalTable;
impl WidthAndMarginsComputer for InternalTable {
/// Compute the used value of width, taking care of min-width and max-width.
impl ISizeAndMarginsComputer for InternalTable {
/// Compute the used value of inline-size, taking care of min-inline-size and max-inline-size.
///
/// CSS Section 10.4: Minimum and Maximum widths
fn compute_used_width(&self,
/// CSS Section 10.4: Minimum and Maximum inline-sizes
fn compute_used_inline_size(&self,
block: &mut BlockFlow,
ctx: &mut LayoutContext,
parent_flow_width: Au) {
let input = self.compute_width_constraint_inputs(block, parent_flow_width, ctx);
let solution = self.solve_width_constraints(block, &input);
self.set_width_constraint_solutions(block, solution);
parent_flow_inline_size: Au) {
let input = self.compute_inline_size_constraint_inputs(block, parent_flow_inline_size, ctx);
let solution = self.solve_inline_size_constraints(block, &input);
self.set_inline_size_constraint_solutions(block, solution);
}
/// Solve the width and margins constraints for this block flow.
fn solve_width_constraints(&self, _: &mut BlockFlow, input: &WidthConstraintInput)
-> WidthConstraintSolution {
WidthConstraintSolution::new(input.available_width, Au::new(0), Au::new(0))
/// Solve the inline-size and margins constraints for this block flow.
fn solve_inline_size_constraints(&self, _: &mut BlockFlow, input: &ISizeConstraintInput)
-> ISizeConstraintSolution {
ISizeConstraintSolution::new(input.available_inline_size, Au::new(0), Au::new(0))
}
}

Просмотреть файл

@ -47,18 +47,18 @@ impl Flow for TableCaptionFlow {
&mut self.block_flow
}
fn bubble_widths(&mut self, ctx: &mut LayoutContext) {
self.block_flow.bubble_widths(ctx);
fn bubble_inline_sizes(&mut self, ctx: &mut LayoutContext) {
self.block_flow.bubble_inline_sizes(ctx);
}
fn assign_widths(&mut self, ctx: &mut LayoutContext) {
debug!("assign_widths({}): assigning width for flow", "table_caption");
self.block_flow.assign_widths(ctx);
fn assign_inline_sizes(&mut self, ctx: &mut LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_caption");
self.block_flow.assign_inline_sizes(ctx);
}
fn assign_height(&mut self, ctx: &mut LayoutContext) {
debug!("assign_height: assigning height for table_caption");
self.block_flow.assign_height(ctx);
fn assign_block_size(&mut self, ctx: &mut LayoutContext) {
debug!("assign_block_size: assigning block_size for table_caption");
self.block_flow.assign_block_size(ctx);
}
fn compute_absolute_position(&mut self) {

Просмотреть файл

@ -6,7 +6,7 @@
#![deny(unsafe_block)]
use block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer};
use block::{BlockFlow, MarginsMayNotCollapse, ISizeAndMarginsComputer};
use context::LayoutContext;
use flow::{TableCellFlowClass, FlowClass, Flow};
use fragment::Fragment;
@ -38,15 +38,15 @@ impl TableCellFlow {
&mut self.block_flow.fragment
}
/// Assign height for table-cell flow.
/// Assign block-size for table-cell flow.
///
/// TODO(#2015, pcwalton): This doesn't handle floats right.
///
/// inline(always) because this is only ever called by in-order or non-in-order top-level
/// methods
#[inline(always)]
fn assign_height_table_cell_base(&mut self, layout_context: &mut LayoutContext) {
self.block_flow.assign_height_block_base(layout_context, MarginsMayNotCollapse)
fn assign_block_size_table_cell_base(&mut self, layout_context: &mut LayoutContext) {
self.block_flow.assign_block_size_block_base(layout_context, MarginsMayNotCollapse)
}
pub fn build_display_list_table_cell(&mut self, layout_context: &LayoutContext) {
@ -68,45 +68,45 @@ impl Flow for TableCellFlow {
&mut self.block_flow
}
/// Minimum/preferred widths set by this function are used in automatic table layout calculation.
fn bubble_widths(&mut self, ctx: &mut LayoutContext) {
self.block_flow.bubble_widths(ctx);
let specified_width = MaybeAuto::from_style(self.block_flow.fragment.style().get_box().width,
/// Minimum/preferred inline-sizes set by this function are used in automatic table layout calculation.
fn bubble_inline_sizes(&mut self, ctx: &mut LayoutContext) {
self.block_flow.bubble_inline_sizes(ctx);
let specified_inline_size = MaybeAuto::from_style(self.block_flow.fragment.style().content_inline_size(),
Au::new(0)).specified_or_zero();
if self.block_flow.base.intrinsic_widths.minimum_width < specified_width {
self.block_flow.base.intrinsic_widths.minimum_width = specified_width;
if self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size < specified_inline_size {
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = specified_inline_size;
}
if self.block_flow.base.intrinsic_widths.preferred_width <
self.block_flow.base.intrinsic_widths.minimum_width {
self.block_flow.base.intrinsic_widths.preferred_width =
self.block_flow.base.intrinsic_widths.minimum_width;
if self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size <
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size {
self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size =
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size;
}
}
/// Recursively (top-down) determines the actual width of child contexts and fragments. When
/// called on this context, the context has had its width set by the parent table row.
fn assign_widths(&mut self, ctx: &mut LayoutContext) {
debug!("assign_widths({}): assigning width for flow", "table_cell");
/// 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 table row.
fn assign_inline_sizes(&mut self, ctx: &mut LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_cell");
// The position was set to the column width by the parent flow, table row flow.
let containing_block_width = self.block_flow.base.position.size.width;
// The position was set to the column inline-size by the parent flow, table row flow.
let containing_block_inline_size = self.block_flow.base.position.size.inline;
let width_computer = InternalTable;
width_computer.compute_used_width(&mut self.block_flow, ctx, containing_block_width);
let inline_size_computer = InternalTable;
inline_size_computer.compute_used_inline_size(&mut self.block_flow, ctx, containing_block_inline_size);
let left_content_edge = self.block_flow.fragment.border_box.origin.x +
self.block_flow.fragment.border_padding.left;
let padding_and_borders = self.block_flow.fragment.border_padding.horizontal();
let content_width = self.block_flow.fragment.border_box.size.width - padding_and_borders;
let inline_start_content_edge = self.block_flow.fragment.border_box.start.i +
self.block_flow.fragment.border_padding.inline_start;
let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end();
let content_inline_size = self.block_flow.fragment.border_box.size.inline - padding_and_borders;
self.block_flow.propagate_assigned_width_to_children(left_content_edge,
content_width,
self.block_flow.propagate_assigned_inline_size_to_children(inline_start_content_edge,
content_inline_size,
None);
}
fn assign_height(&mut self, ctx: &mut LayoutContext) {
debug!("assign_height: assigning height for table_cell");
self.assign_height_table_cell_base(ctx);
fn assign_block_size(&mut self, ctx: &mut LayoutContext) {
debug!("assign_block_size: assigning block_size for table_cell");
self.assign_block_size_table_cell_base(ctx);
}
fn compute_absolute_position(&mut self) {

Просмотреть файл

@ -26,8 +26,8 @@ pub struct TableColGroupFlow {
/// The table column fragments
pub cols: Vec<Fragment>,
/// The specified widths of table columns
pub widths: Vec<Au>,
/// The specified inline-sizes of table columns
pub inline_sizes: Vec<Au>,
}
impl TableColGroupFlow {
@ -38,7 +38,7 @@ impl TableColGroupFlow {
base: BaseFlow::new((*node).clone()),
fragment: Some(fragment),
cols: fragments,
widths: vec!(),
inline_sizes: vec!(),
}
}
}
@ -52,10 +52,10 @@ impl Flow for TableColGroupFlow {
self
}
fn bubble_widths(&mut self, _: &mut LayoutContext) {
fn bubble_inline_sizes(&mut self, _: &mut LayoutContext) {
for fragment in self.cols.iter() {
// get the specified value from width property
let width = MaybeAuto::from_style(fragment.style().get_box().width,
// get the specified value from inline-size property
let inline_size = MaybeAuto::from_style(fragment.style().content_inline_size(),
Au::new(0)).specified_or_zero();
let span: int = match fragment.specific {
@ -63,18 +63,18 @@ impl Flow for TableColGroupFlow {
_ => fail!("Other fragment come out in TableColGroupFlow. {:?}", fragment.specific)
};
for _ in range(0, span) {
self.widths.push(width);
self.inline_sizes.push(inline_size);
}
}
}
/// Table column widths are assigned in table flow and propagated to table row or rowgroup flow.
/// Therefore, table colgroup flow does not need to assign its width.
fn assign_widths(&mut self, _ctx: &mut LayoutContext) {
/// Table column inline-sizes are assigned in table flow and propagated to table row or rowgroup flow.
/// Therefore, table colgroup flow does not need to assign its inline-size.
fn assign_inline_sizes(&mut self, _ctx: &mut LayoutContext) {
}
/// Table column do not have height.
fn assign_height(&mut self, _ctx: &mut LayoutContext) {
/// Table column do not have block-size.
fn assign_block_size(&mut self, _ctx: &mut LayoutContext) {
}
}

Просмотреть файл

@ -7,7 +7,7 @@
#![deny(unsafe_block)]
use block::BlockFlow;
use block::WidthAndMarginsComputer;
use block::ISizeAndMarginsComputer;
use construct::FlowConstructor;
use context::LayoutContext;
use flow::{TableRowFlowClass, FlowClass, Flow, ImmutableFlowUtils};
@ -25,14 +25,14 @@ use std::fmt;
pub struct TableRowFlow {
pub block_flow: BlockFlow,
/// Column widths.
pub col_widths: Vec<Au>,
/// Column inline-sizes.
pub col_inline_sizes: Vec<Au>,
/// Column min widths.
pub col_min_widths: Vec<Au>,
/// Column min inline-sizes.
pub col_min_inline_sizes: Vec<Au>,
/// Column pref widths.
pub col_pref_widths: Vec<Au>,
/// Column pref inline-sizes.
pub col_pref_inline_sizes: Vec<Au>,
}
impl TableRowFlow {
@ -41,9 +41,9 @@ impl TableRowFlow {
-> TableRowFlow {
TableRowFlow {
block_flow: BlockFlow::from_node_and_fragment(node, fragment),
col_widths: vec!(),
col_min_widths: vec!(),
col_pref_widths: vec!(),
col_inline_sizes: vec!(),
col_min_inline_sizes: vec!(),
col_pref_inline_sizes: vec!(),
}
}
@ -52,9 +52,9 @@ impl TableRowFlow {
-> TableRowFlow {
TableRowFlow {
block_flow: BlockFlow::from_node(constructor, node),
col_widths: vec!(),
col_min_widths: vec!(),
col_pref_widths: vec!(),
col_inline_sizes: vec!(),
col_min_inline_sizes: vec!(),
col_pref_inline_sizes: vec!(),
}
}
@ -63,68 +63,68 @@ impl TableRowFlow {
}
fn initialize_offsets(&mut self) -> (Au, Au, Au) {
// TODO: If border-collapse: collapse, top_offset, bottom_offset, and left_offset
// TODO: If border-collapse: collapse, block-start_offset, block-end_offset, and inline-start_offset
// should be updated. Currently, they are set as Au(0).
(Au(0), Au(0), Au(0))
}
/// Assign height for table-row flow.
/// Assign block-size for table-row flow.
///
/// TODO(pcwalton): This doesn't handle floats and positioned elements right.
///
/// inline(always) because this is only ever called by in-order or non-in-order top-level
/// methods
#[inline(always)]
fn assign_height_table_row_base(&mut self, layout_context: &mut LayoutContext) {
let (top_offset, _, _) = self.initialize_offsets();
fn assign_block_size_table_row_base(&mut self, layout_context: &mut LayoutContext) {
let (block_start_offset, _, _) = self.initialize_offsets();
let /* mut */ cur_y = top_offset;
let /* mut */ cur_y = block_start_offset;
// Per CSS 2.1 § 17.5.3, find max_y = max( computed `height`, minimum height of all cells )
// Per CSS 2.1 § 17.5.3, find max_y = max( computed `block-size`, minimum block-size of all cells )
let mut max_y = Au::new(0);
for kid in self.block_flow.base.child_iter() {
kid.assign_height_for_inorder_child_if_necessary(layout_context);
kid.assign_block_size_for_inorder_child_if_necessary(layout_context);
{
let child_fragment = kid.as_table_cell().fragment();
// TODO: Percentage height
let child_specified_height = MaybeAuto::from_style(child_fragment.style().get_box().height,
// TODO: Percentage block-size
let child_specified_block_size = MaybeAuto::from_style(child_fragment.style().content_block_size(),
Au::new(0)).specified_or_zero();
max_y =
geometry::max(max_y,
child_specified_height + child_fragment.border_padding.vertical());
child_specified_block_size + child_fragment.border_padding.block_start_end());
}
let child_node = flow::mut_base(kid);
child_node.position.origin.y = cur_y;
max_y = geometry::max(max_y, child_node.position.size.height);
child_node.position.start.b = cur_y;
max_y = geometry::max(max_y, child_node.position.size.block);
}
let mut height = max_y;
// TODO: Percentage height
height = match MaybeAuto::from_style(self.block_flow.fragment.style().get_box().height, Au(0)) {
Auto => height,
Specified(value) => geometry::max(value, height)
let mut block_size = max_y;
// TODO: Percentage block-size
block_size = match MaybeAuto::from_style(self.block_flow.fragment.style().content_block_size(), Au(0)) {
Auto => block_size,
Specified(value) => geometry::max(value, block_size)
};
// cur_y = cur_y + height;
// cur_y = cur_y + block-size;
// Assign the height of own fragment
// Assign the block-size of own fragment
//
// FIXME(pcwalton): Take `cur_y` into account.
let mut position = self.block_flow.fragment.border_box;
position.size.height = height;
position.size.block = block_size;
self.block_flow.fragment.border_box = position;
self.block_flow.base.position.size.height = height;
self.block_flow.base.position.size.block = block_size;
// Assign the height of kid fragments, which is the same value as own height.
// Assign the block-size of kid fragments, which is the same value as own block-size.
for kid in self.block_flow.base.child_iter() {
{
let kid_fragment = kid.as_table_cell().mut_fragment();
let mut position = kid_fragment.border_box;
position.size.height = height;
position.size.block = block_size;
kid_fragment.border_box = position;
}
let child_node = flow::mut_base(kid);
child_node.position.size.height = height;
child_node.position.size.block = block_size;
}
}
@ -147,70 +147,70 @@ impl Flow for TableRowFlow {
&mut self.block_flow
}
fn col_widths<'a>(&'a mut self) -> &'a mut Vec<Au> {
&mut self.col_widths
fn col_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<Au> {
&mut self.col_inline_sizes
}
fn col_min_widths<'a>(&'a self) -> &'a Vec<Au> {
&self.col_min_widths
fn col_min_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
&self.col_min_inline_sizes
}
fn col_pref_widths<'a>(&'a self) -> &'a Vec<Au> {
&self.col_pref_widths
fn col_pref_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
&self.col_pref_inline_sizes
}
/// Recursively (bottom-up) determines the context's preferred and minimum widths. When called
/// on this context, all child contexts have had their min/pref widths set. This function must
/// decide min/pref widths based on child context widths and dimensions of any fragments it is
/// Recursively (bottom-up) determines the context's preferred and minimum inline-sizes. When called
/// on this context, all child contexts have had their min/pref inline-sizes set. This function must
/// decide min/pref inline-sizes based on child context inline-sizes and dimensions of any fragments it is
/// responsible for flowing.
/// Min/pref widths set by this function are used in automatic table layout calculation.
/// The specified column widths of children cells are used in fixed table layout calculation.
fn bubble_widths(&mut self, _: &mut LayoutContext) {
let mut min_width = Au(0);
let mut pref_width = Au(0);
/* find the specified widths from child table-cell contexts */
/// Min/pref inline-sizes set by this function are used in automatic table layout calculation.
/// The specified column inline-sizes of children cells are used in fixed table layout calculation.
fn bubble_inline_sizes(&mut self, _: &mut LayoutContext) {
let mut min_inline_size = Au(0);
let mut pref_inline_size = Au(0);
/* find the specified inline_sizes from child table-cell contexts */
for kid in self.block_flow.base.child_iter() {
assert!(kid.is_table_cell());
// collect the specified column widths of cells. These are used in fixed table layout calculation.
// collect the specified column inline-sizes of cells. These are used in fixed table layout calculation.
{
let child_fragment = kid.as_table_cell().fragment();
let child_specified_width = MaybeAuto::from_style(child_fragment.style().get_box().width,
let child_specified_inline_size = MaybeAuto::from_style(child_fragment.style().content_inline_size(),
Au::new(0)).specified_or_zero();
self.col_widths.push(child_specified_width);
self.col_inline_sizes.push(child_specified_inline_size);
}
// collect min_width & pref_width of children cells for automatic table layout calculation.
// collect min_inline-size & pref_inline-size of children cells for automatic table layout calculation.
let child_base = flow::mut_base(kid);
self.col_min_widths.push(child_base.intrinsic_widths.minimum_width);
self.col_pref_widths.push(child_base.intrinsic_widths.preferred_width);
min_width = min_width + child_base.intrinsic_widths.minimum_width;
pref_width = pref_width + child_base.intrinsic_widths.preferred_width;
self.col_min_inline_sizes.push(child_base.intrinsic_inline_sizes.minimum_inline_size);
self.col_pref_inline_sizes.push(child_base.intrinsic_inline_sizes.preferred_inline_size);
min_inline_size = min_inline_size + child_base.intrinsic_inline_sizes.minimum_inline_size;
pref_inline_size = pref_inline_size + child_base.intrinsic_inline_sizes.preferred_inline_size;
}
self.block_flow.base.intrinsic_widths.minimum_width = min_width;
self.block_flow.base.intrinsic_widths.preferred_width = geometry::max(min_width,
pref_width);
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = min_inline_size;
self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size = geometry::max(min_inline_size,
pref_inline_size);
}
/// Recursively (top-down) determines the actual width of child contexts and fragments. When called
/// on this context, the context has had its width set by the parent context.
fn assign_widths(&mut self, ctx: &mut LayoutContext) {
debug!("assign_widths({}): assigning width for flow", "table_row");
/// 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.
fn assign_inline_sizes(&mut self, ctx: &mut LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_row");
// The position was set to the containing block by the flow's parent.
let containing_block_width = self.block_flow.base.position.size.width;
// FIXME: In case of border-collapse: collapse, left_content_edge should be border-left
let left_content_edge = Au::new(0);
let containing_block_inline_size = self.block_flow.base.position.size.inline;
// FIXME: In case of border-collapse: collapse, inline-start_content_edge should be border-inline-start
let inline_start_content_edge = Au::new(0);
let width_computer = InternalTable;
width_computer.compute_used_width(&mut self.block_flow, ctx, containing_block_width);
let inline_size_computer = InternalTable;
inline_size_computer.compute_used_inline_size(&mut self.block_flow, ctx, containing_block_inline_size);
self.block_flow.propagate_assigned_width_to_children(left_content_edge, Au(0), Some(self.col_widths.clone()));
self.block_flow.propagate_assigned_inline_size_to_children(inline_start_content_edge, Au(0), Some(self.col_inline_sizes.clone()));
}
fn assign_height(&mut self, ctx: &mut LayoutContext) {
debug!("assign_height: assigning height for table_row");
self.assign_height_table_row_base(ctx);
fn assign_block_size(&mut self, ctx: &mut LayoutContext) {
debug!("assign_block_size: assigning block_size for table_row");
self.assign_block_size_table_row_base(ctx);
}
fn compute_absolute_position(&mut self) {

Просмотреть файл

@ -7,7 +7,7 @@
#![deny(unsafe_block)]
use block::BlockFlow;
use block::WidthAndMarginsComputer;
use block::ISizeAndMarginsComputer;
use construct::FlowConstructor;
use context::LayoutContext;
use flow::{TableRowGroupFlowClass, FlowClass, Flow, ImmutableFlowUtils};
@ -24,14 +24,14 @@ use std::fmt;
pub struct TableRowGroupFlow {
pub block_flow: BlockFlow,
/// Column widths
pub col_widths: Vec<Au>,
/// Column inline-sizes
pub col_inline_sizes: Vec<Au>,
/// Column min widths.
pub col_min_widths: Vec<Au>,
/// Column min inline-sizes.
pub col_min_inline_sizes: Vec<Au>,
/// Column pref widths.
pub col_pref_widths: Vec<Au>,
/// Column pref inline-sizes.
pub col_pref_inline_sizes: Vec<Au>,
}
impl TableRowGroupFlow {
@ -40,9 +40,9 @@ impl TableRowGroupFlow {
-> TableRowGroupFlow {
TableRowGroupFlow {
block_flow: BlockFlow::from_node_and_fragment(node, fragment),
col_widths: vec!(),
col_min_widths: vec!(),
col_pref_widths: vec!(),
col_inline_sizes: vec!(),
col_min_inline_sizes: vec!(),
col_pref_inline_sizes: vec!(),
}
}
@ -51,9 +51,9 @@ impl TableRowGroupFlow {
-> TableRowGroupFlow {
TableRowGroupFlow {
block_flow: BlockFlow::from_node(constructor, node),
col_widths: vec!(),
col_min_widths: vec!(),
col_pref_widths: vec!(),
col_inline_sizes: vec!(),
col_min_inline_sizes: vec!(),
col_pref_inline_sizes: vec!(),
}
}
@ -62,37 +62,37 @@ impl TableRowGroupFlow {
}
fn initialize_offsets(&mut self) -> (Au, Au, Au) {
// TODO: If border-collapse: collapse, top_offset, bottom_offset, and left_offset
// TODO: If border-collapse: collapse, block-start_offset, block-end_offset, and inline-start_offset
// should be updated. Currently, they are set as Au(0).
(Au(0), Au(0), Au(0))
}
/// Assign height for table-rowgroup flow.
/// Assign block-size for table-rowgroup flow.
///
/// FIXME(pcwalton): This doesn't handle floats right.
///
/// inline(always) because this is only ever called by in-order or non-in-order top-level
/// methods
#[inline(always)]
fn assign_height_table_rowgroup_base(&mut self, layout_context: &mut LayoutContext) {
let (top_offset, _, _) = self.initialize_offsets();
fn assign_block_size_table_rowgroup_base(&mut self, layout_context: &mut LayoutContext) {
let (block_start_offset, _, _) = self.initialize_offsets();
let mut cur_y = top_offset;
let mut cur_y = block_start_offset;
for kid in self.block_flow.base.child_iter() {
kid.assign_height_for_inorder_child_if_necessary(layout_context);
kid.assign_block_size_for_inorder_child_if_necessary(layout_context);
let child_node = flow::mut_base(kid);
child_node.position.origin.y = cur_y;
cur_y = cur_y + child_node.position.size.height;
child_node.position.start.b = cur_y;
cur_y = cur_y + child_node.position.size.block;
}
let height = cur_y - top_offset;
let block_size = cur_y - block_start_offset;
let mut position = self.block_flow.fragment.border_box;
position.size.height = height;
position.size.block = block_size;
self.block_flow.fragment.border_box = position;
self.block_flow.base.position.size.height = height;
self.block_flow.base.position.size.block = block_size;
}
pub fn build_display_list_table_rowgroup(&mut self, layout_context: &LayoutContext) {
@ -114,85 +114,86 @@ impl Flow for TableRowGroupFlow {
&mut self.block_flow
}
fn col_widths<'a>(&'a mut self) -> &'a mut Vec<Au> {
&mut self.col_widths
fn col_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<Au> {
&mut self.col_inline_sizes
}
fn col_min_widths<'a>(&'a self) -> &'a Vec<Au> {
&self.col_min_widths
fn col_min_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
&self.col_min_inline_sizes
}
fn col_pref_widths<'a>(&'a self) -> &'a Vec<Au> {
&self.col_pref_widths
fn col_pref_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
&self.col_pref_inline_sizes
}
/// Recursively (bottom-up) determines the context's preferred and minimum widths. When called
/// on this context, all child contexts have had their min/pref widths set. This function must
/// decide min/pref widths based on child context widths and dimensions of any fragments it is
/// Recursively (bottom-up) determines the context's preferred and minimum inline-sizes. When called
/// on this context, all child contexts have had their min/pref inline-sizes set. This function must
/// decide min/pref inline-sizes based on child context inline-sizes and dimensions of any fragments it is
/// responsible for flowing.
/// Min/pref widths set by this function are used in automatic table layout calculation.
/// Also, this function finds the specified column widths from the first row.
/// Min/pref inline-sizes set by this function are used in automatic table layout calculation.
/// Also, this function finds the specified column inline-sizes from the first row.
/// Those are used in fixed table layout calculation
fn bubble_widths(&mut self, _: &mut LayoutContext) {
let mut min_width = Au(0);
let mut pref_width = Au(0);
fn bubble_inline_sizes(&mut self, _: &mut LayoutContext) {
let mut min_inline_size = Au(0);
let mut pref_inline_size = Au(0);
for kid in self.block_flow.base.child_iter() {
assert!(kid.is_table_row());
// calculate min_width & pref_width for automatic table layout calculation
// 'self.col_min_widths' collects the maximum value of cells' min-widths for each column.
// 'self.col_pref_widths' collects the maximum value of cells' pref-widths for each column.
if self.col_widths.is_empty() { // First Row
assert!(self.col_min_widths.is_empty() && self.col_pref_widths.is_empty());
// 'self.col_widths' collects the specified column widths from the first table-row for fixed table layout calculation.
self.col_widths = kid.col_widths().clone();
self.col_min_widths = kid.col_min_widths().clone();
self.col_pref_widths = kid.col_pref_widths().clone();
// calculate min_inline-size & pref_inline-size for automatic table layout calculation
// 'self.col_min_inline-sizes' collects the maximum value of cells' min-inline-sizes for each column.
// 'self.col_pref_inline-sizes' collects the maximum value of cells' pref-inline-sizes for each column.
if self.col_inline_sizes.is_empty() { // First Row
assert!(self.col_min_inline_sizes.is_empty() && self.col_pref_inline_sizes.is_empty());
// 'self.col_inline-sizes' collects the specified column inline-sizes from the first table-row for fixed table layout calculation.
self.col_inline_sizes = kid.col_inline_sizes().clone();
self.col_min_inline_sizes = kid.col_min_inline_sizes().clone();
self.col_pref_inline_sizes = kid.col_pref_inline_sizes().clone();
} else {
min_width = TableFlow::update_col_widths(&mut self.col_min_widths, kid.col_min_widths());
pref_width = TableFlow::update_col_widths(&mut self.col_pref_widths, kid.col_pref_widths());
min_inline_size = TableFlow::update_col_inline_sizes(&mut self.col_min_inline_sizes, kid.col_min_inline_sizes());
pref_inline_size = TableFlow::update_col_inline_sizes(&mut self.col_pref_inline_sizes, kid.col_pref_inline_sizes());
// update the number of column widths from table-rows.
let num_cols = self.col_widths.len();
let num_child_cols = kid.col_min_widths().len();
// update the number of column inline-sizes from table-rows.
let num_cols = self.col_inline_sizes.len();
let num_child_cols = kid.col_min_inline_sizes().len();
for i in range(num_cols, num_child_cols) {
self.col_widths.push(Au::new(0));
let new_kid_min = *kid.col_min_widths().get(i);
self.col_min_widths.push(*kid.col_min_widths().get(i));
let new_kid_pref = *kid.col_pref_widths().get(i);
self.col_pref_widths.push(*kid.col_pref_widths().get(i));
min_width = min_width + new_kid_min;
pref_width = pref_width + new_kid_pref;
self.col_inline_sizes.push(Au::new(0));
let new_kid_min = *kid.col_min_inline_sizes().get(i);
self.col_min_inline_sizes.push(*kid.col_min_inline_sizes().get(i));
let new_kid_pref = *kid.col_pref_inline_sizes().get(i);
self.col_pref_inline_sizes.push(*kid.col_pref_inline_sizes().get(i));
min_inline_size = min_inline_size + new_kid_min;
pref_inline_size = pref_inline_size + new_kid_pref;
}
}
}
self.block_flow.base.intrinsic_widths.minimum_width = min_width;
self.block_flow.base.intrinsic_widths.preferred_width = geometry::max(min_width,
pref_width);
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = min_inline_size;
self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size = geometry::max(min_inline_size,
pref_inline_size);
}
/// Recursively (top-down) determines the actual width of child contexts and fragments. When
/// called on this context, the context has had its width set by the parent context.
fn assign_widths(&mut self, ctx: &mut LayoutContext) {
debug!("assign_widths({}): assigning width for flow", "table_rowgroup");
/// 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.
fn assign_inline_sizes(&mut self, ctx: &mut LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_rowgroup");
// The position was set to the containing block by the flow's parent.
let containing_block_width = self.block_flow.base.position.size.width;
// FIXME: In case of border-collapse: collapse, left_content_edge should be border-left
let left_content_edge = Au::new(0);
let content_width = containing_block_width;
let containing_block_inline_size = self.block_flow.base.position.size.inline;
// FIXME: In case of border-collapse: collapse, inline-start_content_edge should be
// the border width on the inline-start side.
let inline_start_content_edge = Au::new(0);
let content_inline_size = containing_block_inline_size;
let width_computer = InternalTable;
width_computer.compute_used_width(&mut self.block_flow, ctx, containing_block_width);
let inline_size_computer = InternalTable;
inline_size_computer.compute_used_inline_size(&mut self.block_flow, ctx, containing_block_inline_size);
self.block_flow.propagate_assigned_width_to_children(left_content_edge, content_width, Some(self.col_widths.clone()));
self.block_flow.propagate_assigned_inline_size_to_children(inline_start_content_edge, content_inline_size, Some(self.col_inline_sizes.clone()));
}
fn assign_height(&mut self, ctx: &mut LayoutContext) {
debug!("assign_height: assigning height for table_rowgroup");
self.assign_height_table_rowgroup_base(ctx);
fn assign_block_size(&mut self, ctx: &mut LayoutContext) {
debug!("assign_block_size: assigning block_size for table_rowgroup");
self.assign_block_size_table_rowgroup_base(ctx);
}
fn compute_absolute_position(&mut self) {

Просмотреть файл

@ -6,8 +6,8 @@
#![deny(unsafe_block)]
use block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer};
use block::{WidthConstraintInput, WidthConstraintSolution};
use block::{BlockFlow, MarginsMayNotCollapse, ISizeAndMarginsComputer};
use block::{ISizeConstraintInput, ISizeConstraintSolution};
use construct::FlowConstructor;
use context::LayoutContext;
use floats::FloatKind;
@ -30,8 +30,8 @@ pub enum TableLayout {
pub struct TableWrapperFlow {
pub block_flow: BlockFlow,
/// Column widths
pub col_widths: Vec<Au>,
/// Column inline-sizes
pub col_inline_sizes: Vec<Au>,
/// Table-layout property
pub table_layout: TableLayout,
@ -50,7 +50,7 @@ impl TableWrapperFlow {
};
TableWrapperFlow {
block_flow: block_flow,
col_widths: vec!(),
col_inline_sizes: vec!(),
table_layout: table_layout
}
}
@ -67,7 +67,7 @@ impl TableWrapperFlow {
};
TableWrapperFlow {
block_flow: block_flow,
col_widths: vec!(),
col_inline_sizes: vec!(),
table_layout: table_layout
}
}
@ -85,7 +85,7 @@ impl TableWrapperFlow {
};
TableWrapperFlow {
block_flow: block_flow,
col_widths: vec!(),
col_inline_sizes: vec!(),
table_layout: table_layout
}
}
@ -94,14 +94,14 @@ impl TableWrapperFlow {
self.block_flow.float.is_some()
}
/// Assign height for table-wrapper flow.
/// `Assign height` of table-wrapper flow follows a similar process to that of block flow.
/// Assign block-size for table-wrapper flow.
/// `Assign block-size` of table-wrapper flow follows a similar process to that of block flow.
///
/// inline(always) because this is only ever called by in-order or non-in-order top-level
/// methods
#[inline(always)]
fn assign_height_table_wrapper_base(&mut self, layout_context: &mut LayoutContext) {
self.block_flow.assign_height_block_base(layout_context, MarginsMayNotCollapse);
fn assign_block_size_table_wrapper_base(&mut self, layout_context: &mut LayoutContext) {
self.block_flow.assign_block_size_block_base(layout_context, MarginsMayNotCollapse);
}
pub fn build_display_list_table_wrapper(&mut self, layout_context: &LayoutContext) {
@ -124,31 +124,31 @@ impl Flow for TableWrapperFlow {
}
/* Recursively (bottom-up) determine the context's preferred and
minimum widths. When called on this context, all child contexts
have had their min/pref widths set. This function must decide
min/pref widths based on child context widths and dimensions of
minimum inline_sizes. When called on this context, all child contexts
have had their min/pref inline_sizes set. This function must decide
min/pref inline_sizes based on child context inline_sizes and dimensions of
any fragments it is responsible for flowing. */
fn bubble_widths(&mut self, ctx: &mut LayoutContext) {
// get column widths info from table flow
fn bubble_inline_sizes(&mut self, ctx: &mut LayoutContext) {
// get column inline-sizes info from table flow
for kid in self.block_flow.base.child_iter() {
assert!(kid.is_table_caption() || kid.is_table());
if kid.is_table() {
self.col_widths.push_all(kid.as_table().col_widths.as_slice());
self.col_inline_sizes.push_all(kid.as_table().col_inline_sizes.as_slice());
}
}
self.block_flow.bubble_widths(ctx);
self.block_flow.bubble_inline_sizes(ctx);
}
/// Recursively (top-down) determines the actual width of child contexts and fragments. When
/// called on this context, the context has had its width set by the parent context.
/// 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.
///
/// Dual fragments consume some width 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.
fn assign_widths(&mut self, ctx: &mut LayoutContext) {
debug!("assign_widths({}): assigning width for flow",
fn assign_inline_sizes(&mut self, ctx: &mut LayoutContext) {
debug!("assign_inline_sizes({}): assigning inline_size for flow",
if self.is_float() {
"floated table_wrapper"
} else {
@ -156,35 +156,35 @@ impl Flow for TableWrapperFlow {
});
// The position was set to the containing block by the flow's parent.
let containing_block_width = self.block_flow.base.position.size.width;
let containing_block_inline_size = self.block_flow.base.position.size.inline;
let width_computer = TableWrapper;
width_computer.compute_used_width_table_wrapper(self, ctx, containing_block_width);
let inline_size_computer = TableWrapper;
inline_size_computer.compute_used_inline_size_table_wrapper(self, ctx, containing_block_inline_size);
let left_content_edge = self.block_flow.fragment.border_box.origin.x;
let content_width = self.block_flow.fragment.border_box.size.width;
let inline_start_content_edge = self.block_flow.fragment.border_box.start.i;
let content_inline_size = self.block_flow.fragment.border_box.size.inline;
match self.table_layout {
FixedLayout | _ if self.is_float() =>
self.block_flow.base.position.size.width = content_width,
self.block_flow.base.position.size.inline = content_inline_size,
_ => {}
}
// In case of fixed layout, column widths are calculated in table flow.
let assigned_col_widths = match self.table_layout {
// In case of fixed layout, column inline-sizes are calculated in table flow.
let assigned_col_inline_sizes = match self.table_layout {
FixedLayout => None,
AutoLayout => Some(self.col_widths.clone())
AutoLayout => Some(self.col_inline_sizes.clone())
};
self.block_flow.propagate_assigned_width_to_children(left_content_edge, content_width, assigned_col_widths);
self.block_flow.propagate_assigned_inline_size_to_children(inline_start_content_edge, content_inline_size, assigned_col_inline_sizes);
}
fn assign_height(&mut self, ctx: &mut LayoutContext) {
fn assign_block_size(&mut self, ctx: &mut LayoutContext) {
if self.is_float() {
debug!("assign_height_float: assigning height for floated table_wrapper");
self.block_flow.assign_height_float(ctx);
debug!("assign_block_size_float: assigning block_size for floated table_wrapper");
self.block_flow.assign_block_size_float(ctx);
} else {
debug!("assign_height: assigning height for table_wrapper");
self.assign_height_table_wrapper_base(ctx);
debug!("assign_block_size: assigning block_size for table_wrapper");
self.assign_block_size_table_wrapper_base(ctx);
}
}
@ -206,119 +206,120 @@ impl fmt::Show for TableWrapperFlow {
struct TableWrapper;
impl TableWrapper {
fn compute_used_width_table_wrapper(&self,
fn compute_used_inline_size_table_wrapper(&self,
table_wrapper: &mut TableWrapperFlow,
ctx: &mut LayoutContext,
parent_flow_width: Au) {
let input = self.compute_width_constraint_inputs_table_wrapper(table_wrapper,
parent_flow_width,
parent_flow_inline_size: Au) {
let input = self.compute_inline_size_constraint_inputs_table_wrapper(table_wrapper,
parent_flow_inline_size,
ctx);
let solution = self.solve_width_constraints(&mut table_wrapper.block_flow, &input);
let solution = self.solve_inline_size_constraints(&mut table_wrapper.block_flow, &input);
self.set_width_constraint_solutions(&mut table_wrapper.block_flow, solution);
self.set_inline_size_constraint_solutions(&mut table_wrapper.block_flow, solution);
self.set_flow_x_coord_if_necessary(&mut table_wrapper.block_flow, solution);
}
fn compute_width_constraint_inputs_table_wrapper(&self,
fn compute_inline_size_constraint_inputs_table_wrapper(&self,
table_wrapper: &mut TableWrapperFlow,
parent_flow_width: Au,
parent_flow_inline_size: Au,
ctx: &mut LayoutContext)
-> WidthConstraintInput {
let mut input = self.compute_width_constraint_inputs(&mut table_wrapper.block_flow,
parent_flow_width,
-> ISizeConstraintInput {
let mut input = self.compute_inline_size_constraint_inputs(&mut table_wrapper.block_flow,
parent_flow_inline_size,
ctx);
let computed_width = match table_wrapper.table_layout {
let computed_inline_size = match table_wrapper.table_layout {
FixedLayout => {
let fixed_cells_width = table_wrapper.col_widths.iter().fold(Au(0),
|sum, width| sum.add(width));
let fixed_cells_inline_size = table_wrapper.col_inline_sizes.iter().fold(Au(0),
|sum, inline_size| sum.add(inline_size));
let mut computed_width = input.computed_width.specified_or_zero();
let mut computed_inline_size = input.computed_inline_size.specified_or_zero();
let style = table_wrapper.block_flow.fragment.style();
// Get left and right paddings, borders for table.
// Get inline-start and inline-end paddings, borders for table.
// We get these values from the fragment's style since table_wrapper doesn't have it's own border or padding.
// input.available_width is same as containing_block_width in table_wrapper.
let padding_left = specified(style.get_padding().padding_left,
input.available_width);
let padding_right = specified(style.get_padding().padding_right,
input.available_width);
let border_left = style.get_border().border_left_width;
let border_right = style.get_border().border_right_width;
let padding_and_borders = padding_left + padding_right + border_left + border_right;
// Compare border-edge widths. Because fixed_cells_width indicates content-width,
// padding and border values are added to fixed_cells_width.
computed_width = geometry::max(fixed_cells_width + padding_and_borders, computed_width);
computed_width
// input.available_inline-size is same as containing_block_inline-size in table_wrapper.
let padding = style.logical_padding();
let border = style.logical_border_width();
let padding_and_borders =
specified(padding.inline_start, input.available_inline_size) +
specified(padding.inline_end, input.available_inline_size) +
border.inline_start +
border.inline_end;
// Compare border-edge inline-sizes. Because fixed_cells_inline-size indicates content-inline-size,
// padding and border values are added to fixed_cells_inline-size.
computed_inline_size = geometry::max(
fixed_cells_inline_size + padding_and_borders, computed_inline_size);
computed_inline_size
},
AutoLayout => {
// Automatic table layout is calculated according to CSS 2.1 § 17.5.2.2.
let mut cap_min = Au(0);
let mut cols_min = Au(0);
let mut cols_max = Au(0);
let mut col_min_widths = &vec!();
let mut col_pref_widths = &vec!();
let mut col_min_inline_sizes = &vec!();
let mut col_pref_inline_sizes = &vec!();
for kid in table_wrapper.block_flow.base.child_iter() {
if kid.is_table_caption() {
cap_min = kid.as_block().base.intrinsic_widths.minimum_width;
cap_min = kid.as_block().base.intrinsic_inline_sizes.minimum_inline_size;
} else {
assert!(kid.is_table());
cols_min = kid.as_block().base.intrinsic_widths.minimum_width;
cols_max = kid.as_block().base.intrinsic_widths.preferred_width;
col_min_widths = kid.col_min_widths();
col_pref_widths = kid.col_pref_widths();
cols_min = kid.as_block().base.intrinsic_inline_sizes.minimum_inline_size;
cols_max = kid.as_block().base.intrinsic_inline_sizes.preferred_inline_size;
col_min_inline_sizes = kid.col_min_inline_sizes();
col_pref_inline_sizes = kid.col_pref_inline_sizes();
}
}
// 'extra_width': difference between the calculated table width and minimum width
// 'extra_inline-size': difference between the calculated table inline-size and minimum inline-size
// required by all columns. It will be distributed over the columns.
let (width, extra_width) = match input.computed_width {
let (inline_size, extra_inline_size) = match input.computed_inline_size {
Auto => {
if input.available_width > geometry::max(cols_max, cap_min) {
if input.available_inline_size > geometry::max(cols_max, cap_min) {
if cols_max > cap_min {
table_wrapper.col_widths = col_pref_widths.clone();
table_wrapper.col_inline_sizes = col_pref_inline_sizes.clone();
(cols_max, Au(0))
} else {
(cap_min, cap_min - cols_min)
}
} else {
let max = if cols_min >= input.available_width && cols_min >= cap_min {
table_wrapper.col_widths = col_min_widths.clone();
let max = if cols_min >= input.available_inline_size && cols_min >= cap_min {
table_wrapper.col_inline_sizes = col_min_inline_sizes.clone();
cols_min
} else {
geometry::max(input.available_width, cap_min)
geometry::max(input.available_inline_size, cap_min)
};
(max, max - cols_min)
}
},
Specified(width) => {
let max = if cols_min >= width && cols_min >= cap_min {
table_wrapper.col_widths = col_min_widths.clone();
Specified(inline_size) => {
let max = if cols_min >= inline_size && cols_min >= cap_min {
table_wrapper.col_inline_sizes = col_min_inline_sizes.clone();
cols_min
} else {
geometry::max(width, cap_min)
geometry::max(inline_size, cap_min)
};
(max, max - cols_min)
}
};
// The extra width is distributed over the columns
if extra_width > Au(0) {
let cell_len = table_wrapper.col_widths.len() as f64;
table_wrapper.col_widths = col_min_widths.iter().map(|width| {
width + extra_width.scale_by(1.0 / cell_len)
// The extra inline-size is distributed over the columns
if extra_inline_size > Au(0) {
let cell_len = table_wrapper.col_inline_sizes.len() as f64;
table_wrapper.col_inline_sizes = col_min_inline_sizes.iter().map(|inline_size| {
inline_size + extra_inline_size.scale_by(1.0 / cell_len)
}).collect();
}
width
inline_size
}
};
input.computed_width = Specified(computed_width);
input.computed_inline_size = Specified(computed_inline_size);
input
}
}
impl WidthAndMarginsComputer for TableWrapper {
/// Solve the width and margins constraints for this block flow.
fn solve_width_constraints(&self, block: &mut BlockFlow, input: &WidthConstraintInput)
-> WidthConstraintSolution {
self.solve_block_width_constraints(block, input)
impl ISizeAndMarginsComputer for TableWrapper {
/// Solve the inline-size and margins constraints for this block flow.
fn solve_inline_size_constraints(&self, block: &mut BlockFlow, input: &ISizeConstraintInput)
-> ISizeConstraintSolution {
self.solve_block_inline_size_constraints(block, input)
}
}

Просмотреть файл

@ -15,6 +15,7 @@ use gfx::text::glyph::CharIndex;
use gfx::text::text_run::TextRun;
use gfx::text::util::{CompressWhitespaceNewline, transform_text, CompressNone};
use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalSize;
use servo_util::range::Range;
use style::ComputedValues;
use style::computed_values::{font_family, line_height, white_space};
@ -151,9 +152,11 @@ impl TextRunScanner {
*text);
let range = Range::new(CharIndex(0), run.char_len());
let new_metrics = run.metrics_for_range(&range);
let bounding_box_size = LogicalSize::from_physical(
old_fragment.style.writing_mode, new_metrics.bounding_box.size);
let new_text_fragment_info = ScannedTextFragmentInfo::new(Arc::new(run), range);
let mut new_fragment = old_fragment.transform(new_metrics.bounding_box.size,
ScannedTextFragment(new_text_fragment_info));
let mut new_fragment = old_fragment.transform(
bounding_box_size, ScannedTextFragment(new_text_fragment_info));
new_fragment.new_line_pos = new_line_pos;
out_fragments.push(new_fragment)
}
@ -236,9 +239,12 @@ impl TextRunScanner {
}
let new_text_fragment_info = ScannedTextFragmentInfo::new(run.get_ref().clone(), *range);
let old_fragment = &in_fragments[i.to_uint()];
let new_metrics = new_text_fragment_info.run.metrics_for_range(range);
let mut new_fragment = in_fragments[i.to_uint()].transform(new_metrics.bounding_box.size,
ScannedTextFragment(new_text_fragment_info));
let bounding_box_size = LogicalSize::from_physical(
old_fragment.style.writing_mode, new_metrics.bounding_box.size);
let mut new_fragment = old_fragment.transform(
bounding_box_size, ScannedTextFragment(new_text_fragment_info));
new_fragment.new_line_pos = new_line_positions.get(logical_offset.to_uint()).new_line_pos.clone();
out_fragments.push(new_fragment)
}
@ -288,7 +294,7 @@ pub fn computed_style_to_font_style(style: &ComputedValues) -> FontStyle {
}
}
/// Returns the line height needed by the given computed style and font size.
/// Returns the line block-size needed by the given computed style and font size.
///
/// FIXME(pcwalton): I believe this should not take a separate `font-size` parameter.
pub fn line_height_from_style(style: &ComputedValues, font_size: Au) -> Au {

Просмотреть файл

@ -97,6 +97,7 @@ pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
#[cfg(not(test))]
pub fn run(opts: opts::Opts) {
::servo_util::opts::set_experimental_enabled(opts.enable_experimental);
RegisterBindings::RegisterProxyHandlers();
let mut pool_config = green::PoolConfig::new();

Просмотреть файл

@ -8,11 +8,13 @@ pub use std::ascii::StrAsciiExt;
use serialize::{Encodable, Encoder};
pub use servo_util::url::parse_url;
use servo_util::logical_geometry::{WritingMode, LogicalMargin};
use sync::Arc;
pub use url::Url;
pub use cssparser::*;
pub use cssparser::ast::*;
pub use geom::SideOffsets2D;
use errors::{ErrorLoggerIterator, log_css_error};
pub use parsing_utils::*;
@ -35,7 +37,7 @@ def to_rust_ident(name):
return name
class Longhand(object):
def __init__(self, name, derived_from=None):
def __init__(self, name, derived_from=None, experimental=False):
self.name = name
self.ident = to_rust_ident(name)
self.camel_case, _ = re.subn(
@ -43,6 +45,7 @@ class Longhand(object):
lambda m: m.group(1).upper(),
self.ident.strip("_").capitalize())
self.style_struct = THIS_STYLE_STRUCT
self.experimental = experimental
if derived_from is None:
self.derived_from = None
else:
@ -94,12 +97,12 @@ pub mod longhands {
value
}
<%def name="raw_longhand(name, no_super=False, derived_from=None)">
<%def name="raw_longhand(name, no_super=False, derived_from=None, experimental=False)">
<%
if derived_from is not None:
derived_from = derived_from.split()
property = Longhand(name, derived_from=derived_from)
property = Longhand(name, derived_from=derived_from, experimental=experimental)
THIS_STYLE_STRUCT.longhands.append(property)
LONGHANDS.append(property)
LONGHANDS_BY_NAME[name] = property
@ -128,8 +131,9 @@ pub mod longhands {
}
</%def>
<%def name="longhand(name, no_super=False, derived_from=None)">
<%self:raw_longhand name="${name}" derived_from="${derived_from}">
<%def name="longhand(name, no_super=False, derived_from=None, experimental=False)">
<%self:raw_longhand name="${name}" derived_from="${derived_from}"
experimental="${experimental}">
${caller.body()}
% if derived_from is None:
pub fn parse_specified(_input: &[ComponentValue], _base_url: &Url)
@ -140,8 +144,9 @@ pub mod longhands {
</%self:raw_longhand>
</%def>
<%def name="single_component_value(name, derived_from=None)">
<%self:longhand name="${name}" derived_from="${derived_from}">
<%def name="single_component_value(name, derived_from=None, experimental=False)">
<%self:longhand name="${name}" derived_from="${derived_from}"
experimental="${experimental}">
${caller.body()}
pub fn parse(input: &[ComponentValue], base_url: &Url) -> Option<SpecifiedValue> {
one_component_value(input).and_then(|c| from_component_value(c, base_url))
@ -149,8 +154,8 @@ pub mod longhands {
</%self:longhand>
</%def>
<%def name="single_keyword_computed(name, values)">
<%self:single_component_value name="${name}">
<%def name="single_keyword_computed(name, values, experimental=False)">
<%self:single_component_value name="${name}" experimental="${experimental}">
${caller.body()}
pub mod computed_value {
#[allow(non_camel_case_types)]
@ -179,9 +184,10 @@ pub mod longhands {
</%self:single_component_value>
</%def>
<%def name="single_keyword(name, values)">
<%def name="single_keyword(name, values, experimental=False)">
<%self:single_keyword_computed name="${name}"
values="${values}">
values="${values}"
experimental="${experimental}">
// The computed value is the same as the specified value.
pub use to_computed_value = super::computed_as_specified;
</%self:single_keyword_computed>
@ -323,7 +329,7 @@ pub mod longhands {
${new_style_struct("InheritedBox", is_inherited=True)}
${single_keyword("direction", "ltr rtl")}
${single_keyword("direction", "ltr rtl", experimental=True)}
// CSS 2.1, Section 10 - Visual formatting model details
@ -1041,11 +1047,11 @@ pub mod longhands {
// http://dev.w3.org/csswg/css-writing-modes/
${switch_to_style_struct("InheritedBox")}
${single_keyword("writing-mode", "horizontal-tb vertical-rl vertical-lr")}
${single_keyword("writing-mode", "horizontal-tb vertical-rl vertical-lr", experimental=True)}
// FIXME(SimonSapin): Add 'mixed' and 'upright' (needs vertical text support)
// FIXME(SimonSapin): initial (first) value should be 'mixed', when that's implemented
${single_keyword("text-orientation", "sideways sideways-left sideways-right")}
${single_keyword("text-orientation", "sideways sideways-left sideways-right", experimental=True)}
}
@ -1436,6 +1442,10 @@ pub fn parse_property_declaration_list<I: Iterator<Node>>(input: I, base_url: &U
match PropertyDeclaration::parse(n.as_slice(), v.as_slice(), list, base_url, seen) {
UnknownProperty => log_css_error(l, format!(
"Unsupported property: {}:{}", n, v.iter().to_css()).as_slice()),
ExperimentalProperty => log_css_error(l, format!(
"Experimental property, use `servo --enable_experimental` \
or `servo -e` to enable: {}:{}",
n, v.iter().to_css()).as_slice()),
InvalidValue => log_css_error(l, format!(
"Invalid value: {}:{}", n, v.iter().to_css()).as_slice()),
ValidOrIgnoredDeclaration => (),
@ -1486,6 +1496,7 @@ pub enum PropertyDeclaration {
pub enum PropertyDeclarationParseResult {
UnknownProperty,
ExperimentalProperty,
InvalidValue,
ValidOrIgnoredDeclaration,
}
@ -1502,6 +1513,11 @@ impl PropertyDeclaration {
% for property in LONGHANDS:
% if property.derived_from is None:
"${property.name}" => {
% if property.experimental:
if !::servo_util::opts::experimental_enabled() {
return ExperimentalProperty
}
% endif
if seen.get_${property.ident}() {
return ValidOrIgnoredDeclaration
}
@ -1576,8 +1592,6 @@ impl PropertyDeclaration {
pub mod style_structs {
use super::longhands;
use super::computed_values;
use servo_util::logical_geometry::WritingMode;
% for style_struct in STYLE_STRUCTS:
#[deriving(PartialEq, Clone)]
@ -1587,42 +1601,6 @@ pub mod style_structs {
% endfor
}
% endfor
impl InheritedBox {
/// Return a WritingMode bitflags from the relevant CSS properties.
pub fn get_writing_mode(&self) -> WritingMode {
use servo_util::logical_geometry;
let mut flags = WritingMode::empty();
match self.direction {
computed_values::direction::ltr => {},
computed_values::direction::rtl => {
flags.insert(logical_geometry::FlagRTL);
},
}
match self.writing_mode {
computed_values::writing_mode::horizontal_tb => {},
computed_values::writing_mode::vertical_rl => {
flags.insert(logical_geometry::FlagVertical);
},
computed_values::writing_mode::vertical_lr => {
flags.insert(logical_geometry::FlagVertical);
flags.insert(logical_geometry::FlagVerticalLR);
},
}
match self.text_orientation {
computed_values::text_orientation::sideways_right => {},
computed_values::text_orientation::sideways_left => {
flags.insert(logical_geometry::FlagSidewaysLeft);
},
computed_values::text_orientation::sideways => {
if flags.intersects(logical_geometry::FlagVerticalLR) {
flags.insert(logical_geometry::FlagSidewaysLeft);
}
},
}
flags
}
}
}
#[deriving(Clone)]
@ -1631,6 +1609,7 @@ pub struct ComputedValues {
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
% endfor
shareable: bool,
pub writing_mode: WritingMode,
}
impl ComputedValues {
@ -1648,7 +1627,89 @@ impl ComputedValues {
}
}
#[inline]
pub fn content_inline_size(&self) -> computed_values::LengthOrPercentageOrAuto {
let box_style = self.get_box();
if self.writing_mode.is_vertical() { box_style.height } else { box_style.width }
}
#[inline]
pub fn content_block_size(&self) -> computed_values::LengthOrPercentageOrAuto {
let box_style = self.get_box();
if self.writing_mode.is_vertical() { box_style.width } else { box_style.height }
}
#[inline]
pub fn min_inline_size(&self) -> computed_values::LengthOrPercentage {
let box_style = self.get_box();
if self.writing_mode.is_vertical() { box_style.min_height } else { box_style.min_width }
}
#[inline]
pub fn min_block_size(&self) -> computed_values::LengthOrPercentage {
let box_style = self.get_box();
if self.writing_mode.is_vertical() { box_style.min_width } else { box_style.min_height }
}
#[inline]
pub fn max_inline_size(&self) -> computed_values::LengthOrPercentageOrNone {
let box_style = self.get_box();
if self.writing_mode.is_vertical() { box_style.max_height } else { box_style.max_width }
}
#[inline]
pub fn max_block_size(&self) -> computed_values::LengthOrPercentageOrNone {
let box_style = self.get_box();
if self.writing_mode.is_vertical() { box_style.max_width } else { box_style.max_height }
}
#[inline]
pub fn logical_padding(&self) -> LogicalMargin<computed_values::LengthOrPercentage> {
let padding_style = self.get_padding();
LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
padding_style.padding_top,
padding_style.padding_right,
padding_style.padding_bottom,
padding_style.padding_left,
))
}
#[inline]
pub fn logical_border_width(&self) -> LogicalMargin<Au> {
let border_style = self.get_border();
LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
border_style.border_top_width,
border_style.border_right_width,
border_style.border_bottom_width,
border_style.border_left_width,
))
}
#[inline]
pub fn logical_margin(&self) -> LogicalMargin<computed_values::LengthOrPercentageOrAuto> {
let margin_style = self.get_margin();
LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
margin_style.margin_top,
margin_style.margin_right,
margin_style.margin_bottom,
margin_style.margin_left,
))
}
#[inline]
pub fn logical_position(&self) -> LogicalMargin<computed_values::LengthOrPercentageOrAuto> {
// FIXME(SimonSapin): should be the writing mode of the containing block, maybe?
let position_style = self.get_positionoffsets();
LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
position_style.top,
position_style.right,
position_style.bottom,
position_style.left,
))
}
% for style_struct in STYLE_STRUCTS:
#[inline]
pub fn get_${style_struct.name.lower()}
<'a>(&'a self) -> &'a style_structs::${style_struct.name} {
&*self.${style_struct.ident}
@ -1656,6 +1717,42 @@ impl ComputedValues {
% endfor
}
/// Return a WritingMode bitflags from the relevant CSS properties.
fn get_writing_mode(inheritedbox_style: &style_structs::InheritedBox) -> WritingMode {
use servo_util::logical_geometry;
let mut flags = WritingMode::empty();
match inheritedbox_style.direction {
computed_values::direction::ltr => {},
computed_values::direction::rtl => {
flags.insert(logical_geometry::FlagRTL);
},
}
match inheritedbox_style.writing_mode {
computed_values::writing_mode::horizontal_tb => {},
computed_values::writing_mode::vertical_rl => {
flags.insert(logical_geometry::FlagVertical);
},
computed_values::writing_mode::vertical_lr => {
flags.insert(logical_geometry::FlagVertical);
flags.insert(logical_geometry::FlagVerticalLR);
},
}
match inheritedbox_style.text_orientation {
computed_values::text_orientation::sideways_right => {},
computed_values::text_orientation::sideways_left => {
flags.insert(logical_geometry::FlagSidewaysLeft);
},
computed_values::text_orientation::sideways => {
if flags.intersects(logical_geometry::FlagVerticalLR) {
flags.insert(logical_geometry::FlagSidewaysLeft);
}
},
}
flags
}
/// The initial values for all style structs as defined by the specification.
lazy_init! {
static ref INITIAL_VALUES: ComputedValues = ComputedValues {
@ -1667,10 +1764,17 @@ lazy_init! {
}),
% endfor
shareable: true,
writing_mode: WritingMode::empty()
};
}
#[test]
fn initial_writing_mode_is_empty() {
assert_eq!(get_writing_mode(INITIAL_VALUES.get_inheritedbox()), WritingMode::empty())
}
/// This only exists to limit the scope of #[allow(experimental)]
/// FIXME: remove this when Arc::make_unique() is not experimental anymore.
trait ArcExperimental<T> {
@ -1766,6 +1870,7 @@ fn cascade_with_cached_declarations(applicable_declarations: &[MatchedProperty],
}
ComputedValues {
writing_mode: get_writing_mode(&*style_inheritedbox),
% for style_struct in STYLE_STRUCTS:
${style_struct.ident}: style_${style_struct.ident},
% endfor
@ -1984,6 +2089,7 @@ pub fn cascade(applicable_declarations: &[MatchedProperty],
}
(ComputedValues {
writing_mode: get_writing_mode(&*style_inheritedbox),
% for style_struct in STYLE_STRUCTS:
${style_struct.ident}: style_${style_struct.ident},
% endfor
@ -2009,6 +2115,7 @@ pub fn cascade_anonymous(parent_style: &ComputedValues) -> ComputedValues {
.${style_struct.ident}.clone(),
% endfor
shareable: false,
writing_mode: parent_style.writing_mode,
};
{
let border = result.border.make_unique_experimental();

Просмотреть файл

@ -17,6 +17,7 @@
extern crate debug;
extern crate collections;
extern crate geom;
extern crate num;
extern crate serialize;
extern crate sync;

Просмотреть файл

@ -67,7 +67,7 @@ pub enum PagePx {}
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.
//
// FIXME: Implement Au using Length and ScaleFactor instead of a custom type.
#[deriving(Clone, PartialEq, PartialOrd, Zero)]
#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Zero)]
pub struct Au(pub i32);
impl Default for Au {

Просмотреть файл

@ -5,6 +5,7 @@
/// Geometry in flow-relative space.
use geom::{Size2D, Point2D, SideOffsets2D, Rect};
use std::cmp::{min, max};
use std::fmt::{Show, Formatter, FormatError};
use std::num::Zero;
@ -130,15 +131,15 @@ impl Show for DebugWritingMode {
/// A 2D size in flow-relative dimensions
#[deriving(PartialEq, Eq, Clone)]
pub struct LogicalSize<T> {
pub isize: T, // inline-size (a.k.a. logical width)
pub bsize: T, // block-size (a.k.a. logical height)
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
debug_writing_mode: DebugWritingMode,
}
impl<T: Show> Show for LogicalSize<T> {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FormatError> {
write!(formatter, "LogicalSize[{}, {}, {}]",
self.debug_writing_mode, self.isize, self.bsize)
self.debug_writing_mode, self.inline, self.block)
}
}
@ -147,24 +148,24 @@ impl<T: Zero> LogicalSize<T> {
#[inline]
pub fn zero(mode: WritingMode) -> LogicalSize<T> {
LogicalSize {
isize: Zero::zero(),
bsize: Zero::zero(),
inline: Zero::zero(),
block: Zero::zero(),
debug_writing_mode: DebugWritingMode::new(mode),
}
}
#[inline]
pub fn is_zero(&self) -> bool {
self.isize.is_zero() && self.bsize.is_zero()
self.inline.is_zero() && self.block.is_zero()
}
}
impl<T: Copy> LogicalSize<T> {
#[inline]
pub fn new(mode: WritingMode, isize: T, bsize: T) -> LogicalSize<T> {
pub fn new(mode: WritingMode, inline: T, block: T) -> LogicalSize<T> {
LogicalSize {
isize: isize,
bsize: bsize,
inline: inline,
block: block,
debug_writing_mode: DebugWritingMode::new(mode),
}
}
@ -182,9 +183,9 @@ impl<T: Copy> LogicalSize<T> {
pub fn width(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
self.bsize
self.block
} else {
self.isize
self.inline
}
}
@ -192,9 +193,9 @@ impl<T: Copy> LogicalSize<T> {
pub fn set_width(&mut self, mode: WritingMode, width: T) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
self.bsize = width
self.block = width
} else {
self.isize = width
self.inline = width
}
}
@ -202,9 +203,9 @@ impl<T: Copy> LogicalSize<T> {
pub fn height(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
self.isize
self.inline
} else {
self.bsize
self.block
}
}
@ -212,9 +213,9 @@ impl<T: Copy> LogicalSize<T> {
pub fn set_height(&mut self, mode: WritingMode, height: T) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
self.isize = height
self.inline = height
} else {
self.bsize = height
self.block = height
}
}
@ -222,9 +223,9 @@ impl<T: Copy> LogicalSize<T> {
pub fn to_physical(&self, mode: WritingMode) -> Size2D<T> {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
Size2D { width: self.bsize, height: self.isize }
Size2D { width: self.block, height: self.inline }
} else {
Size2D { width: self.isize, height: self.bsize }
Size2D { width: self.inline, height: self.block }
}
}
@ -245,8 +246,8 @@ impl<T: Add<T, T>> Add<LogicalSize<T>, LogicalSize<T>> for LogicalSize<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
LogicalSize {
debug_writing_mode: self.debug_writing_mode,
isize: self.isize + other.isize,
bsize: self.bsize + other.bsize,
inline: self.inline + other.inline,
block: self.block + other.block,
}
}
}
@ -257,8 +258,8 @@ impl<T: Sub<T, T>> Sub<LogicalSize<T>, LogicalSize<T>> for LogicalSize<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
LogicalSize {
debug_writing_mode: self.debug_writing_mode,
isize: self.isize - other.isize,
bsize: self.bsize - other.bsize,
inline: self.inline - other.inline,
block: self.block - other.block,
}
}
}
@ -395,14 +396,28 @@ impl<T: Copy + Sub<T, T>> LogicalPoint<T> {
}
}
impl<T: Add<T,T>> LogicalPoint<T> {
/// This doesnt really makes sense,
/// but happens when dealing with mutliple origins.
#[inline]
pub fn add_point(&self, other: &LogicalPoint<T>) -> LogicalPoint<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
LogicalPoint {
debug_writing_mode: self.debug_writing_mode,
i: self.i + other.i,
b: self.b + other.b,
}
}
}
impl<T: Add<T,T>> Add<LogicalSize<T>, LogicalPoint<T>> for LogicalPoint<T> {
#[inline]
fn add(&self, other: &LogicalSize<T>) -> LogicalPoint<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
LogicalPoint {
debug_writing_mode: self.debug_writing_mode,
i: self.i + other.isize,
b: self.b + other.bsize,
i: self.i + other.inline,
b: self.b + other.block,
}
}
}
@ -413,8 +428,8 @@ impl<T: Sub<T,T>> Sub<LogicalSize<T>, LogicalPoint<T>> for LogicalPoint<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
LogicalPoint {
debug_writing_mode: self.debug_writing_mode,
i: self.i - other.isize,
b: self.b - other.bsize,
i: self.i - other.inline,
b: self.b - other.block,
}
}
}
@ -426,17 +441,20 @@ impl<T: Sub<T,T>> Sub<LogicalSize<T>, LogicalPoint<T>> for LogicalPoint<T> {
/// A positive "margin" can be added to a rectangle to obtain a bigger rectangle.
#[deriving(PartialEq, Eq, Clone)]
pub struct LogicalMargin<T> {
pub bstart: T,
pub iend: T,
pub bend: T,
pub istart: T,
pub block_start: T,
pub inline_end: T,
pub block_end: T,
pub inline_start: T,
debug_writing_mode: DebugWritingMode,
}
impl<T: Show> Show for LogicalMargin<T> {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FormatError> {
write!(formatter, "LogicalMargin[{}, bstart: {}, iend: {}, bend: {}, istart: {}]",
self.debug_writing_mode, self.bstart, self.iend, self.bend, self.istart)
write!(formatter,
"LogicalMargin[{}, block_start: {}, inline_end: {}, \
block_end: {}, inline_start: {}]",
self.debug_writing_mode, self.block_start,
self.inline_end, self.block_end, self.inline_start)
}
}
@ -444,77 +462,83 @@ impl<T: Zero> LogicalMargin<T> {
#[inline]
pub fn zero(mode: WritingMode) -> LogicalMargin<T> {
LogicalMargin {
bstart: Zero::zero(),
iend: Zero::zero(),
bend: Zero::zero(),
istart: Zero::zero(),
block_start: Zero::zero(),
inline_end: Zero::zero(),
block_end: Zero::zero(),
inline_start: Zero::zero(),
debug_writing_mode: DebugWritingMode::new(mode),
}
}
#[inline]
pub fn is_zero(&self) -> bool {
self.bstart.is_zero() &&
self.iend.is_zero() &&
self.bend.is_zero() &&
self.istart.is_zero()
self.block_start.is_zero() &&
self.inline_end.is_zero() &&
self.block_end.is_zero() &&
self.inline_start.is_zero()
}
}
impl<T: Copy> LogicalMargin<T> {
#[inline]
pub fn new(mode: WritingMode, bstart: T, iend: T, bend: T, istart: T) -> LogicalMargin<T> {
pub fn new(mode: WritingMode, block_start: T, inline_end: T, block_end: T, inline_start: T)
-> LogicalMargin<T> {
LogicalMargin {
bstart: bstart,
iend: iend,
bend: bend,
istart: istart,
block_start: block_start,
inline_end: inline_end,
block_end: block_end,
inline_start: inline_start,
debug_writing_mode: DebugWritingMode::new(mode),
}
}
#[inline]
pub fn new_all_same(mode: WritingMode, value: T) -> LogicalMargin<T> {
LogicalMargin::new(mode, value, value, value, value)
}
#[inline]
pub fn from_physical(mode: WritingMode, offsets: SideOffsets2D<T>) -> LogicalMargin<T> {
let bstart;
let iend;
let bend;
let istart;
let block_start;
let inline_end;
let block_end;
let inline_start;
if mode.is_vertical() {
if mode.is_vertical_lr() {
bstart = offsets.left;
bend = offsets.right;
block_start = offsets.left;
block_end = offsets.right;
} else {
bstart = offsets.right;
bend = offsets.left;
block_start = offsets.right;
block_end = offsets.left;
}
if mode.is_inline_tb() {
istart = offsets.top;
iend = offsets.bottom;
inline_start = offsets.top;
inline_end = offsets.bottom;
} else {
istart = offsets.bottom;
iend = offsets.top;
inline_start = offsets.bottom;
inline_end = offsets.top;
}
} else {
bstart = offsets.top;
bend = offsets.bottom;
block_start = offsets.top;
block_end = offsets.bottom;
if mode.is_bidi_ltr() {
istart = offsets.left;
iend = offsets.right;
inline_start = offsets.left;
inline_end = offsets.right;
} else {
istart = offsets.right;
iend = offsets.left;
inline_start = offsets.right;
inline_end = offsets.left;
}
}
LogicalMargin::new(mode, bstart, iend, bend, istart)
LogicalMargin::new(mode, block_start, inline_end, block_end, inline_start)
}
#[inline]
pub fn top(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_inline_tb() { self.istart } else { self.iend }
if mode.is_inline_tb() { self.inline_start } else { self.inline_end }
} else {
self.bstart
self.block_start
}
}
@ -522,9 +546,9 @@ impl<T: Copy> LogicalMargin<T> {
pub fn set_top(&mut self, mode: WritingMode, top: T) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_inline_tb() { self.istart = top } else { self.iend = top }
if mode.is_inline_tb() { self.inline_start = top } else { self.inline_end = top }
} else {
self.bstart = top
self.block_start = top
}
}
@ -532,9 +556,9 @@ impl<T: Copy> LogicalMargin<T> {
pub fn right(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_vertical_lr() { self.bend } else { self.bstart }
if mode.is_vertical_lr() { self.block_end } else { self.block_start }
} else {
if mode.is_bidi_ltr() { self.iend } else { self.istart }
if mode.is_bidi_ltr() { self.inline_end } else { self.inline_start }
}
}
@ -542,9 +566,9 @@ impl<T: Copy> LogicalMargin<T> {
pub fn set_right(&mut self, mode: WritingMode, right: T) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_vertical_lr() { self.bend = right } else { self.bstart = right }
if mode.is_vertical_lr() { self.block_end = right } else { self.block_start = right }
} else {
if mode.is_bidi_ltr() { self.iend = right } else { self.istart = right }
if mode.is_bidi_ltr() { self.inline_end = right } else { self.inline_start = right }
}
}
@ -552,9 +576,9 @@ impl<T: Copy> LogicalMargin<T> {
pub fn bottom(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_inline_tb() { self.iend } else { self.istart }
if mode.is_inline_tb() { self.inline_end } else { self.inline_start }
} else {
self.bend
self.block_end
}
}
@ -562,9 +586,9 @@ impl<T: Copy> LogicalMargin<T> {
pub fn set_bottom(&mut self, mode: WritingMode, bottom: T) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_inline_tb() { self.iend = bottom } else { self.istart = bottom }
if mode.is_inline_tb() { self.inline_end = bottom } else { self.inline_start = bottom }
} else {
self.bend = bottom
self.block_end = bottom
}
}
@ -572,9 +596,9 @@ impl<T: Copy> LogicalMargin<T> {
pub fn left(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_vertical_lr() { self.bstart } else { self.bend }
if mode.is_vertical_lr() { self.block_start } else { self.block_end }
} else {
if mode.is_bidi_ltr() { self.istart } else { self.iend }
if mode.is_bidi_ltr() { self.inline_start } else { self.inline_end }
}
}
@ -582,9 +606,9 @@ impl<T: Copy> LogicalMargin<T> {
pub fn set_left(&mut self, mode: WritingMode, left: T) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_vertical_lr() { self.bstart = left } else { self.bend = left }
if mode.is_vertical_lr() { self.block_start = left } else { self.block_end = left }
} else {
if mode.is_bidi_ltr() { self.istart = left } else { self.iend = left }
if mode.is_bidi_ltr() { self.inline_start = left } else { self.inline_end = left }
}
}
@ -597,28 +621,28 @@ impl<T: Copy> LogicalMargin<T> {
let left;
if mode.is_vertical() {
if mode.is_vertical_lr() {
left = self.bstart;
right = self.bend;
left = self.block_start;
right = self.block_end;
} else {
right = self.bstart;
left = self.bend;
right = self.block_start;
left = self.block_end;
}
if mode.is_inline_tb() {
top = self.istart;
bottom = self.iend;
top = self.inline_start;
bottom = self.inline_end;
} else {
bottom = self.istart;
top = self.iend;
bottom = self.inline_start;
top = self.inline_end;
}
} else {
top = self.bstart;
bottom = self.bend;
top = self.block_start;
bottom = self.block_end;
if mode.is_bidi_ltr() {
left = self.istart;
right = self.iend;
left = self.inline_start;
right = self.inline_end;
} else {
right = self.istart;
left = self.iend;
right = self.inline_start;
left = self.inline_end;
}
}
SideOffsets2D::new(top, right, bottom, left)
@ -637,22 +661,22 @@ impl<T: Copy> LogicalMargin<T> {
impl<T: Add<T, T>> LogicalMargin<T> {
#[inline]
pub fn istart_end(&self) -> T {
self.istart + self.iend
pub fn inline_start_end(&self) -> T {
self.inline_start + self.inline_end
}
#[inline]
pub fn bstart_end(&self) -> T {
self.bstart + self.bend
pub fn block_start_end(&self) -> T {
self.block_start + self.block_end
}
#[inline]
pub fn top_bottom(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
self.istart_end()
self.inline_start_end()
} else {
self.bstart_end()
self.block_start_end()
}
}
@ -660,9 +684,9 @@ impl<T: Add<T, T>> LogicalMargin<T> {
pub fn left_right(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
self.bstart_end()
self.block_start_end()
} else {
self.istart_end()
self.inline_start_end()
}
}
}
@ -673,10 +697,10 @@ impl<T: Add<T, T>> Add<LogicalMargin<T>, LogicalMargin<T>> for LogicalMargin<T>
self.debug_writing_mode.check_debug(other.debug_writing_mode);
LogicalMargin {
debug_writing_mode: self.debug_writing_mode,
bstart: self.bstart + other.bstart,
iend: self.iend + other.iend,
bend: self.bend + other.bend,
istart: self.istart + other.istart,
block_start: self.block_start + other.block_start,
inline_end: self.inline_end + other.inline_end,
block_end: self.block_end + other.block_end,
inline_start: self.inline_start + other.inline_start,
}
}
}
@ -687,10 +711,10 @@ impl<T: Sub<T, T>> Sub<LogicalMargin<T>, LogicalMargin<T>> for LogicalMargin<T>
self.debug_writing_mode.check_debug(other.debug_writing_mode);
LogicalMargin {
debug_writing_mode: self.debug_writing_mode,
bstart: self.bstart - other.bstart,
iend: self.iend - other.iend,
bend: self.bend - other.bend,
istart: self.istart - other.istart,
block_start: self.block_start - other.block_start,
inline_end: self.inline_end - other.inline_end,
block_end: self.block_end - other.block_end,
inline_start: self.inline_start - other.inline_start,
}
}
}
@ -706,9 +730,11 @@ pub struct LogicalRect<T> {
impl<T: Show> Show for LogicalRect<T> {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FormatError> {
write!(formatter, "LogicalRect[{}, istart: {}, bstart: {}, isize: {}, bsize: {}]",
write!(formatter,
"LogicalRect[{}, inline_start: {}, block_start: {}, \
inline: {}, block: {}]",
self.debug_writing_mode, self.start.i, self.start.b,
self.size.isize, self.size.bsize)
self.size.inline, self.size.block)
}
}
@ -730,10 +756,23 @@ impl<T: Zero> LogicalRect<T> {
impl<T: Copy> LogicalRect<T> {
#[inline]
pub fn new(mode: WritingMode, istart: T, bstart: T, isize: T, bsize: T) -> LogicalRect<T> {
pub fn new(mode: WritingMode, inline_start: T, block_start: T, inline: T, block: T)
-> LogicalRect<T> {
LogicalRect {
start: LogicalPoint::new(mode, istart, bstart),
size: LogicalSize::new(mode, isize, bsize),
start: LogicalPoint::new(mode, inline_start, block_start),
size: LogicalSize::new(mode, inline, block),
debug_writing_mode: DebugWritingMode::new(mode),
}
}
#[inline]
pub fn from_point_size(mode: WritingMode, start: LogicalPoint<T>, size: LogicalSize<T>)
-> LogicalRect<T> {
start.debug_writing_mode.check(mode);
size.debug_writing_mode.check(mode);
LogicalRect {
start: start,
size: size,
debug_writing_mode: DebugWritingMode::new(mode),
}
}
@ -743,48 +782,48 @@ impl<T: Copy + Add<T, T> + Sub<T, T>> LogicalRect<T> {
#[inline]
pub fn from_physical(mode: WritingMode, rect: Rect<T>, container_size: Size2D<T>)
-> LogicalRect<T> {
let istart;
let bstart;
let isize;
let bsize;
let inline_start;
let block_start;
let inline;
let block;
if mode.is_vertical() {
isize = rect.size.height;
bsize = rect.size.width;
inline = rect.size.height;
block = rect.size.width;
if mode.is_vertical_lr() {
bstart = rect.origin.x;
block_start = rect.origin.x;
} else {
bstart = container_size.width - (rect.origin.x + rect.size.width);
block_start = container_size.width - (rect.origin.x + rect.size.width);
}
if mode.is_inline_tb() {
istart = rect.origin.y;
inline_start = rect.origin.y;
} else {
istart = container_size.height - (rect.origin.y + rect.size.height);
inline_start = container_size.height - (rect.origin.y + rect.size.height);
}
} else {
isize = rect.size.width;
bsize = rect.size.height;
bstart = rect.origin.y;
inline = rect.size.width;
block = rect.size.height;
block_start = rect.origin.y;
if mode.is_bidi_ltr() {
istart = rect.origin.x;
inline_start = rect.origin.x;
} else {
istart = container_size.width - (rect.origin.x + rect.size.width);
inline_start = container_size.width - (rect.origin.x + rect.size.width);
}
}
LogicalRect {
start: LogicalPoint::new(mode, istart, bstart),
size: LogicalSize::new(mode, isize, bsize),
start: LogicalPoint::new(mode, inline_start, block_start),
size: LogicalSize::new(mode, inline, block),
debug_writing_mode: DebugWritingMode::new(mode),
}
}
#[inline]
pub fn iend(&self) -> T {
self.start.i + self.size.isize
pub fn inline_end(&self) -> T {
self.start.i + self.size.inline
}
#[inline]
pub fn bend(&self) -> T {
self.start.b + self.size.bsize
pub fn block_end(&self) -> T {
self.start.b + self.size.block
}
#[inline]
@ -795,26 +834,26 @@ impl<T: Copy + Add<T, T> + Sub<T, T>> LogicalRect<T> {
let width;
let height;
if mode.is_vertical() {
width = self.size.bsize;
height = self.size.isize;
width = self.size.block;
height = self.size.inline;
if mode.is_vertical_lr() {
x = self.start.b;
} else {
x = container_size.width - self.bend();
x = container_size.width - self.block_end();
}
if mode.is_inline_tb() {
y = self.start.i;
} else {
y = container_size.height - self.iend();
y = container_size.height - self.inline_end();
}
} else {
width = self.size.isize;
height = self.size.bsize;
width = self.size.inline;
height = self.size.block;
y = self.start.b;
if mode.is_bidi_ltr() {
x = self.start.i;
} else {
x = container_size.width - self.iend();
x = container_size.width - self.inline_end();
}
}
Rect {
@ -834,6 +873,41 @@ impl<T: Copy + Add<T, T> + Sub<T, T>> LogicalRect<T> {
mode_to, self.to_physical(mode_from, container_size), container_size)
}
}
pub fn translate(&self, offset: &LogicalPoint<T>) -> LogicalRect<T> {
LogicalRect {
start: self.start + LogicalSize {
inline: offset.i,
block: offset.b,
debug_writing_mode: offset.debug_writing_mode,
},
size: self.size,
debug_writing_mode: self.debug_writing_mode,
}
}
}
impl<T: Copy + Ord + Add<T, T> + Sub<T, T>> LogicalRect<T> {
#[inline]
pub fn union(&self, other: &LogicalRect<T>) -> LogicalRect<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
let inline_start = min(self.start.i, other.start.i);
let block_start = min(self.start.b, other.start.b);
LogicalRect {
start: LogicalPoint {
i: inline_start,
b: block_start,
debug_writing_mode: self.debug_writing_mode,
},
size: LogicalSize {
inline: max(self.inline_end(), other.inline_end()) - inline_start,
block: max(self.block_end(), other.block_end()) - block_start,
debug_writing_mode: self.debug_writing_mode,
},
debug_writing_mode: self.debug_writing_mode,
}
}
}
impl<T: Add<T, T> + Sub<T, T>> Add<LogicalMargin<T>, LogicalRect<T>> for LogicalRect<T> {
@ -844,13 +918,13 @@ impl<T: Add<T, T> + Sub<T, T>> Add<LogicalMargin<T>, LogicalRect<T>> for Logical
start: LogicalPoint {
// Growing a rectangle on the start side means pushing its
// start point on the negative direction.
i: self.start.i - other.istart,
b: self.start.b - other.bstart,
i: self.start.i - other.inline_start,
b: self.start.b - other.block_start,
debug_writing_mode: self.debug_writing_mode,
},
size: LogicalSize {
isize: self.size.isize + other.istart_end(),
bsize: self.size.bsize + other.bstart_end(),
inline: self.size.inline + other.inline_start_end(),
block: self.size.block + other.block_start_end(),
debug_writing_mode: self.debug_writing_mode,
},
debug_writing_mode: self.debug_writing_mode,
@ -867,13 +941,13 @@ impl<T: Add<T, T> + Sub<T, T>> Sub<LogicalMargin<T>, LogicalRect<T>> for Logical
start: LogicalPoint {
// Shrinking a rectangle on the start side means pushing its
// start point on the positive direction.
i: self.start.i + other.istart,
b: self.start.b + other.bstart,
i: self.start.i + other.inline_start,
b: self.start.b + other.block_start,
debug_writing_mode: self.debug_writing_mode,
},
size: LogicalSize {
isize: self.size.isize - other.istart_end(),
bsize: self.size.bsize - other.bstart_end(),
inline: self.size.inline - other.inline_start_end(),
block: self.size.block - other.block_start_end(),
debug_writing_mode: self.debug_writing_mode,
},
debug_writing_mode: self.debug_writing_mode,

Просмотреть файл

@ -49,6 +49,9 @@ pub struct Opts {
/// and cause it to produce output on that interval (`-m`).
pub memory_profiler_period: Option<f64>,
/// Enable experimental web features (`-e`).
pub enable_experimental: bool,
/// The number of threads to use for layout (`-y`). Defaults to 1, which results in a recursive
/// sequential algorithm.
pub layout_threads: uint,
@ -64,7 +67,7 @@ pub struct Opts {
/// intrinsic widths are computed as a separate pass instead of during flow construction. You
/// may wish to turn this flag on in order to benchmark style recalculation against other
/// browser engines.
pub bubble_widths_separately: bool,
pub bubble_inline_sizes_separately: bool,
}
fn print_usage(app: &str, opts: &[getopts::OptGroup]) {
@ -87,6 +90,7 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
getopts::optopt("r", "rendering", "Rendering backend", "direct2d|core-graphics|core-graphics-accelerated|cairo|skia."),
getopts::optopt("s", "size", "Size of tiles", "512"),
getopts::optopt("", "device-pixel-ratio", "Device pixels per px", ""),
getopts::optflag("e", "experimental", "Enable experimental web features"),
getopts::optopt("t", "threads", "Number of render threads", "1"),
getopts::optflagopt("p", "profile", "Profiler flag and output interval", "10"),
getopts::optflagopt("m", "memory-profile", "Memory profiler flag and output interval", "10"),
@ -176,11 +180,26 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
device_pixels_per_px: device_pixels_per_px,
time_profiler_period: time_profiler_period,
memory_profiler_period: memory_profiler_period,
enable_experimental: opt_match.opt_present("e"),
layout_threads: layout_threads,
exit_after_load: opt_match.opt_present("x"),
output_file: opt_match.opt_str("o"),
headless: opt_match.opt_present("z"),
hard_fail: opt_match.opt_present("f"),
bubble_widths_separately: opt_match.opt_present("b"),
bubble_inline_sizes_separately: opt_match.opt_present("b"),
})
}
static mut EXPERIMENTAL_ENABLED: bool = false;
pub fn set_experimental_enabled(new_value: bool) {
unsafe {
EXPERIMENTAL_ENABLED = new_value;
}
}
pub fn experimental_enabled() -> bool {
unsafe {
EXPERIMENTAL_ENABLED
}
}

Просмотреть файл

@ -82,8 +82,8 @@ fn parse_lists(file: &String, servo_args: &[String]) -> Vec<TestDescAndFn> {
};
for line in contents.as_slice().lines() {
// ignore comments
if line.starts_with("#") {
// ignore comments or empty lines
if line.starts_with("#") || line.is_empty() {
continue;
}