зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
56b9ec01ff
Коммит
2453870c2f
|
@ -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 doesn’t 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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче