diff --git a/src/components/embedding/core.rs b/src/components/embedding/core.rs index e6831743990..b3517af877c 100644 --- a/src/components/embedding/core.rs +++ b/src/components/embedding/core.rs @@ -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); diff --git a/src/components/layout/block.rs b/src/components/layout/block.rs index f17582f142a..1812c6bc642 100644 --- a/src/components/layout/block.rs +++ b/src/components/layout/block.rs @@ -21,17 +21,16 @@ use flow::{BaseFlow, BlockFlowClass, FlowClass, Flow, ImmutableFlowUtils}; use flow::{MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal, mut_base}; use flow; use fragment::{Fragment, ImageFragment, ScannedTextFragment}; -use model::{Auto, IntrinsicWidths, MarginCollapseInfo, MarginsCollapse}; +use model::{Auto, IntrinsicISizes, MarginCollapseInfo, MarginsCollapse}; use model::{MarginsCollapseThrough, MaybeAuto, NoCollapsibleMargins, Specified, specified}; use model::{specified_or_none}; -use model; use wrapper::ThreadSafeLayoutNode; use style::ComputedValues; use style::computed_values::{clear, position}; use collections::Deque; use collections::dlist::DList; -use geom::{Point2D, Rect, Size2D}; +use geom::{Size2D, Point2D, Rect}; use gfx::color; use gfx::display_list::{BackgroundAndBorderLevel, BlockLevel, ContentStackingLevel, DisplayList}; use gfx::display_list::{FloatStackingLevel, PositionedDescendantStackingLevel}; @@ -40,20 +39,21 @@ use gfx::render_task::RenderLayer; use servo_msg::compositor_msg::{FixedPosition, LayerId, Scrollable}; use servo_util::geometry::Au; use servo_util::geometry; +use servo_util::logical_geometry::WritingMode; +use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize}; use std::fmt; use std::mem; -use std::num::Zero; use style::computed_values::{LPA_Auto, LPA_Length, LPA_Percentage, LPN_Length, LPN_None}; use style::computed_values::{LPN_Percentage, LP_Length, LP_Percentage}; -use style::computed_values::{display, direction, float, overflow}; +use style::computed_values::{display, float, overflow}; use sync::Arc; /// Information specific to floated blocks. pub struct FloatedBlockInfo { - pub containing_width: Au, + pub containing_inline_size: Au, /// Offset relative to where the parent tried to position this flow - pub rel_pos: Point2D, + pub rel_pos: LogicalPoint, /// Index into the fragment list for inline floats pub index: Option, @@ -63,34 +63,34 @@ pub struct FloatedBlockInfo { } impl FloatedBlockInfo { - pub fn new(float_kind: FloatKind) -> FloatedBlockInfo { + pub fn new(float_kind: FloatKind, writing_mode: WritingMode) -> FloatedBlockInfo { FloatedBlockInfo { - containing_width: Au(0), - rel_pos: Point2D(Au(0), Au(0)), + containing_inline_size: Au(0), + rel_pos: LogicalPoint::new(writing_mode, Au(0), Au(0)), index: None, float_kind: float_kind, } } } -/// The solutions for the heights-and-margins constraint equation. -struct HeightConstraintSolution { - top: Au, - _bottom: Au, - height: Au, - margin_top: Au, - margin_bottom: Au +/// The solutions for the block-size-and-margins constraint equation. +struct BSizeConstraintSolution { + block_start: Au, + _block_end: Au, + block_size: Au, + margin_block_start: Au, + margin_block_end: Au } -impl HeightConstraintSolution { - fn new(top: Au, bottom: Au, height: Au, margin_top: Au, margin_bottom: Au) - -> HeightConstraintSolution { - HeightConstraintSolution { - top: top, - _bottom: bottom, - height: height, - margin_top: margin_top, - margin_bottom: margin_bottom, +impl BSizeConstraintSolution { + fn new(block_start: Au, block_end: Au, block_size: Au, margin_block_start: Au, margin_block_end: Au) + -> BSizeConstraintSolution { + BSizeConstraintSolution { + block_start: block_start, + _block_end: block_end, + block_size: block_size, + margin_block_start: margin_block_start, + margin_block_end: margin_block_end, } } @@ -98,57 +98,57 @@ impl HeightConstraintSolution { /// /// CSS Section 10.6.4 /// Constraint equation: - /// top + bottom + height + margin-top + margin-bottom - /// = absolute containing block height - (vertical padding and border) - /// [aka available_height] + /// block-start + block-end + block-size + margin-block-start + margin-block-end + /// = absolute containing block block-size - (vertical padding and border) + /// [aka available_block-size] /// /// Return the solution for the equation. - fn solve_vertical_constraints_abs_nonreplaced(height: MaybeAuto, - top_margin: MaybeAuto, - bottom_margin: MaybeAuto, - top: MaybeAuto, - bottom: MaybeAuto, - content_height: Au, - available_height: Au, - static_y_offset: Au) - -> HeightConstraintSolution { - // Distance from the top edge of the Absolute Containing Block to the - // top margin edge of a hypothetical box that would have been the + fn solve_vertical_constraints_abs_nonreplaced(block_size: MaybeAuto, + block_start_margin: MaybeAuto, + block_end_margin: MaybeAuto, + block_start: MaybeAuto, + block_end: MaybeAuto, + content_block_size: Au, + available_block_size: Au, + static_b_offset: Au) + -> BSizeConstraintSolution { + // Distance from the block-start edge of the Absolute Containing Block to the + // block-start margin edge of a hypothetical box that would have been the // first box of the element. - let static_position_top = static_y_offset; + let static_position_block_start = static_b_offset; - let (top, bottom, height, margin_top, margin_bottom) = match (top, bottom, height) { + let (block_start, block_end, block_size, margin_block_start, margin_block_end) = match (block_start, block_end, block_size) { (Auto, Auto, Auto) => { - let margin_top = top_margin.specified_or_zero(); - let margin_bottom = bottom_margin.specified_or_zero(); - let top = static_position_top; - // Now it is the same situation as top Specified and bottom - // and height Auto. + let margin_block_start = block_start_margin.specified_or_zero(); + let margin_block_end = block_end_margin.specified_or_zero(); + let block_start = static_position_block_start; + // Now it is the same situation as block-start Specified and block-end + // and block-size Auto. - let height = content_height; - let sum = top + height + margin_top + margin_bottom; - (top, available_height - sum, height, margin_top, margin_bottom) + let block_size = content_block_size; + let sum = block_start + block_size + margin_block_start + margin_block_end; + (block_start, available_block_size - sum, block_size, margin_block_start, margin_block_end) } - (Specified(top), Specified(bottom), Specified(height)) => { - match (top_margin, bottom_margin) { + (Specified(block_start), Specified(block_end), Specified(block_size)) => { + match (block_start_margin, block_end_margin) { (Auto, Auto) => { - let total_margin_val = available_height - top - bottom - height; - (top, bottom, height, + let total_margin_val = available_block_size - block_start - block_end - block_size; + (block_start, block_end, block_size, total_margin_val.scale_by(0.5), total_margin_val.scale_by(0.5)) } - (Specified(margin_top), Auto) => { - let sum = top + bottom + height + margin_top; - (top, bottom, height, margin_top, available_height - sum) + (Specified(margin_block_start), Auto) => { + let sum = block_start + block_end + block_size + margin_block_start; + (block_start, block_end, block_size, margin_block_start, available_block_size - sum) } - (Auto, Specified(margin_bottom)) => { - let sum = top + bottom + height + margin_bottom; - (top, bottom, height, available_height - sum, margin_bottom) + (Auto, Specified(margin_block_end)) => { + let sum = block_start + block_end + block_size + margin_block_end; + (block_start, block_end, block_size, available_block_size - sum, margin_block_end) } - (Specified(margin_top), Specified(margin_bottom)) => { - // Values are over-constrained. Ignore value for 'bottom'. - let sum = top + height + margin_top + margin_bottom; - (top, available_height - sum, height, margin_top, margin_bottom) + (Specified(margin_block_start), Specified(margin_block_end)) => { + // Values are over-constrained. Ignore value for 'block-end'. + let sum = block_start + block_size + margin_block_start + margin_block_end; + (block_start, available_block_size - sum, block_size, margin_block_start, margin_block_end) } } } @@ -156,235 +156,239 @@ impl HeightConstraintSolution { // For the rest of the cases, auto values for margin are set to 0 // If only one is Auto, solve for it - (Auto, Specified(bottom), Specified(height)) => { - let margin_top = top_margin.specified_or_zero(); - let margin_bottom = bottom_margin.specified_or_zero(); - let sum = bottom + height + margin_top + margin_bottom; - (available_height - sum, bottom, height, margin_top, margin_bottom) + (Auto, Specified(block_end), Specified(block_size)) => { + let margin_block_start = block_start_margin.specified_or_zero(); + let margin_block_end = block_end_margin.specified_or_zero(); + let sum = block_end + block_size + margin_block_start + margin_block_end; + (available_block_size - sum, block_end, block_size, margin_block_start, margin_block_end) } - (Specified(top), Auto, Specified(height)) => { - let margin_top = top_margin.specified_or_zero(); - let margin_bottom = bottom_margin.specified_or_zero(); - let sum = top + height + margin_top + margin_bottom; - (top, available_height - sum, height, margin_top, margin_bottom) + (Specified(block_start), Auto, Specified(block_size)) => { + let margin_block_start = block_start_margin.specified_or_zero(); + let margin_block_end = block_end_margin.specified_or_zero(); + let sum = block_start + block_size + margin_block_start + margin_block_end; + (block_start, available_block_size - sum, block_size, margin_block_start, margin_block_end) } - (Specified(top), Specified(bottom), Auto) => { - let margin_top = top_margin.specified_or_zero(); - let margin_bottom = bottom_margin.specified_or_zero(); - let sum = top + bottom + margin_top + margin_bottom; - (top, bottom, available_height - sum, margin_top, margin_bottom) + (Specified(block_start), Specified(block_end), Auto) => { + let margin_block_start = block_start_margin.specified_or_zero(); + let margin_block_end = block_end_margin.specified_or_zero(); + let sum = block_start + block_end + margin_block_start + margin_block_end; + (block_start, block_end, available_block_size - sum, margin_block_start, margin_block_end) } - // If height is auto, then height is content height. Solve for the + // If block-size is auto, then block-size is content block-size. Solve for the // non-auto value. - (Specified(top), Auto, Auto) => { - let margin_top = top_margin.specified_or_zero(); - let margin_bottom = bottom_margin.specified_or_zero(); - let height = content_height; - let sum = top + height + margin_top + margin_bottom; - (top, available_height - sum, height, margin_top, margin_bottom) + (Specified(block_start), Auto, Auto) => { + let margin_block_start = block_start_margin.specified_or_zero(); + let margin_block_end = block_end_margin.specified_or_zero(); + let block_size = content_block_size; + let sum = block_start + block_size + margin_block_start + margin_block_end; + (block_start, available_block_size - sum, block_size, margin_block_start, margin_block_end) } - (Auto, Specified(bottom), Auto) => { - let margin_top = top_margin.specified_or_zero(); - let margin_bottom = bottom_margin.specified_or_zero(); - let height = content_height; - let sum = bottom + height + margin_top + margin_bottom; - (available_height - sum, bottom, height, margin_top, margin_bottom) + (Auto, Specified(block_end), Auto) => { + let margin_block_start = block_start_margin.specified_or_zero(); + let margin_block_end = block_end_margin.specified_or_zero(); + let block_size = content_block_size; + let sum = block_end + block_size + margin_block_start + margin_block_end; + (available_block_size - sum, block_end, block_size, margin_block_start, margin_block_end) } - (Auto, Auto, Specified(height)) => { - let margin_top = top_margin.specified_or_zero(); - let margin_bottom = bottom_margin.specified_or_zero(); - let top = static_position_top; - let sum = top + height + margin_top + margin_bottom; - (top, available_height - sum, height, margin_top, margin_bottom) + (Auto, Auto, Specified(block_size)) => { + let margin_block_start = block_start_margin.specified_or_zero(); + let margin_block_end = block_end_margin.specified_or_zero(); + let block_start = static_position_block_start; + let sum = block_start + block_size + margin_block_start + margin_block_end; + (block_start, available_block_size - sum, block_size, margin_block_start, margin_block_end) } }; - HeightConstraintSolution::new(top, bottom, height, margin_top, margin_bottom) + BSizeConstraintSolution::new(block_start, block_end, block_size, margin_block_start, margin_block_end) } /// Solve the vertical constraint equation for absolute replaced elements. /// - /// Assumption: The used value for height has already been calculated. + /// Assumption: The used value for block-size has already been calculated. /// /// CSS Section 10.6.5 /// Constraint equation: - /// top + bottom + height + margin-top + margin-bottom - /// = absolute containing block height - (vertical padding and border) - /// [aka available_height] + /// block-start + block-end + block-size + margin-block-start + margin-block-end + /// = absolute containing block block-size - (vertical padding and border) + /// [aka available_block-size] /// /// Return the solution for the equation. - fn solve_vertical_constraints_abs_replaced(height: Au, - top_margin: MaybeAuto, - bottom_margin: MaybeAuto, - top: MaybeAuto, - bottom: MaybeAuto, + fn solve_vertical_constraints_abs_replaced(block_size: Au, + block_start_margin: MaybeAuto, + block_end_margin: MaybeAuto, + block_start: MaybeAuto, + block_end: MaybeAuto, _: Au, - available_height: Au, - static_y_offset: Au) - -> HeightConstraintSolution { - // Distance from the top edge of the Absolute Containing Block to the - // top margin edge of a hypothetical box that would have been the + available_block_size: Au, + static_b_offset: Au) + -> BSizeConstraintSolution { + // Distance from the block-start edge of the Absolute Containing Block to the + // block-start margin edge of a hypothetical box that would have been the // first box of the element. - let static_position_top = static_y_offset; + let static_position_block_start = static_b_offset; - let (top, bottom, height, margin_top, margin_bottom) = match (top, bottom) { + let (block_start, block_end, block_size, margin_block_start, margin_block_end) = match (block_start, block_end) { (Auto, Auto) => { - let margin_top = top_margin.specified_or_zero(); - let margin_bottom = bottom_margin.specified_or_zero(); - let top = static_position_top; - let sum = top + height + margin_top + margin_bottom; - (top, available_height - sum, height, margin_top, margin_bottom) + let margin_block_start = block_start_margin.specified_or_zero(); + let margin_block_end = block_end_margin.specified_or_zero(); + let block_start = static_position_block_start; + let sum = block_start + block_size + margin_block_start + margin_block_end; + (block_start, available_block_size - sum, block_size, margin_block_start, margin_block_end) } - (Specified(top), Specified(bottom)) => { - match (top_margin, bottom_margin) { + (Specified(block_start), Specified(block_end)) => { + match (block_start_margin, block_end_margin) { (Auto, Auto) => { - let total_margin_val = available_height - top - bottom - height; - (top, bottom, height, + let total_margin_val = available_block_size - block_start - block_end - block_size; + (block_start, block_end, block_size, total_margin_val.scale_by(0.5), total_margin_val.scale_by(0.5)) } - (Specified(margin_top), Auto) => { - let sum = top + bottom + height + margin_top; - (top, bottom, height, margin_top, available_height - sum) + (Specified(margin_block_start), Auto) => { + let sum = block_start + block_end + block_size + margin_block_start; + (block_start, block_end, block_size, margin_block_start, available_block_size - sum) } - (Auto, Specified(margin_bottom)) => { - let sum = top + bottom + height + margin_bottom; - (top, bottom, height, available_height - sum, margin_bottom) + (Auto, Specified(margin_block_end)) => { + let sum = block_start + block_end + block_size + margin_block_end; + (block_start, block_end, block_size, available_block_size - sum, margin_block_end) } - (Specified(margin_top), Specified(margin_bottom)) => { - // Values are over-constrained. Ignore value for 'bottom'. - let sum = top + height + margin_top + margin_bottom; - (top, available_height - sum, height, margin_top, margin_bottom) + (Specified(margin_block_start), Specified(margin_block_end)) => { + // Values are over-constrained. Ignore value for 'block-end'. + let sum = block_start + block_size + margin_block_start + margin_block_end; + (block_start, available_block_size - sum, block_size, margin_block_start, margin_block_end) } } } // If only one is Auto, solve for it - (Auto, Specified(bottom)) => { - let margin_top = top_margin.specified_or_zero(); - let margin_bottom = bottom_margin.specified_or_zero(); - let sum = bottom + height + margin_top + margin_bottom; - (available_height - sum, bottom, height, margin_top, margin_bottom) + (Auto, Specified(block_end)) => { + let margin_block_start = block_start_margin.specified_or_zero(); + let margin_block_end = block_end_margin.specified_or_zero(); + let sum = block_end + block_size + margin_block_start + margin_block_end; + (available_block_size - sum, block_end, block_size, margin_block_start, margin_block_end) } - (Specified(top), Auto) => { - let margin_top = top_margin.specified_or_zero(); - let margin_bottom = bottom_margin.specified_or_zero(); - let sum = top + height + margin_top + margin_bottom; - (top, available_height - sum, height, margin_top, margin_bottom) + (Specified(block_start), Auto) => { + let margin_block_start = block_start_margin.specified_or_zero(); + let margin_block_end = block_end_margin.specified_or_zero(); + let sum = block_start + block_size + margin_block_start + margin_block_end; + (block_start, available_block_size - sum, block_size, margin_block_start, margin_block_end) } }; - HeightConstraintSolution::new(top, bottom, height, margin_top, margin_bottom) + BSizeConstraintSolution::new(block_start, block_end, block_size, margin_block_start, margin_block_end) } } -/// Performs height calculations potentially multiple times, taking `height`, `min-height`, and -/// `max-height` into account. After each call to `next()`, the caller must call `.try()` with the +/// Performs block-size calculations potentially multiple times, taking +/// (assuming an horizontal writing mode) `height`, `min-height`, and `max-height` +/// into account. After each call to `next()`, the caller must call `.try()` with the /// current calculated value of `height`. /// /// See CSS 2.1 § 10.7. -struct CandidateHeightIterator { - height: MaybeAuto, - max_height: Option, - min_height: Au, +struct CandidateBSizeIterator { + block_size: MaybeAuto, + max_block_size: Option, + min_block_size: Au, candidate_value: Au, - status: CandidateHeightIteratorStatus, + status: CandidateBSizeIteratorStatus, } -impl CandidateHeightIterator { - /// Creates a new candidate height iterator. `block_container_height` is `None` if the height +impl CandidateBSizeIterator { + /// Creates a new candidate block-size iterator. `block_container_block-size` is `None` if the block-size /// of the block container has not been determined yet. It will always be `Some` in the case of /// absolutely-positioned containing blocks. - pub fn new(style: &ComputedValues, block_container_height: Option) - -> CandidateHeightIterator { - // Per CSS 2.1 § 10.7, percentages in `min-height` and `max-height` refer to the height of - // the containing block. If that is not determined yet by the time we need to resolve + pub fn new(style: &ComputedValues, block_container_block_size: Option) + -> CandidateBSizeIterator { + // Per CSS 2.1 § 10.7, (assuming an horizontal writing mode,) + // percentages in `min-height` and `max-height` refer to the height of + // the containing block. + // If that is not determined yet by the time we need to resolve // `min-height` and `max-height`, percentage values are ignored. - let height = match (style.get_box().height, block_container_height) { - (LPA_Percentage(percent), Some(block_container_height)) => { - Specified(block_container_height.scale_by(percent)) + let block_size = match (style.content_block_size(), block_container_block_size) { + (LPA_Percentage(percent), Some(block_container_block_size)) => { + Specified(block_container_block_size.scale_by(percent)) } (LPA_Percentage(_), None) | (LPA_Auto, _) => Auto, (LPA_Length(length), _) => Specified(length), }; - let max_height = match (style.get_box().max_height, block_container_height) { - (LPN_Percentage(percent), Some(block_container_height)) => { - Some(block_container_height.scale_by(percent)) + let max_block_size = match (style.max_block_size(), block_container_block_size) { + (LPN_Percentage(percent), Some(block_container_block_size)) => { + Some(block_container_block_size.scale_by(percent)) } (LPN_Percentage(_), None) | (LPN_None, _) => None, (LPN_Length(length), _) => Some(length), }; - let min_height = match (style.get_box().min_height, block_container_height) { - (LP_Percentage(percent), Some(block_container_height)) => { - block_container_height.scale_by(percent) + let min_block_size = match (style.min_block_size(), block_container_block_size) { + (LP_Percentage(percent), Some(block_container_block_size)) => { + block_container_block_size.scale_by(percent) } (LP_Percentage(_), None) => Au(0), (LP_Length(length), _) => length, }; - CandidateHeightIterator { - height: height, - max_height: max_height, - min_height: min_height, + CandidateBSizeIterator { + block_size: block_size, + max_block_size: max_block_size, + min_block_size: min_block_size, candidate_value: Au(0), - status: InitialCandidateHeightStatus, + status: InitialCandidateBSizeStatus, } } pub fn next<'a>(&'a mut self) -> Option<(MaybeAuto, &'a mut Au)> { self.status = match self.status { - InitialCandidateHeightStatus => TryingHeightCandidateHeightStatus, - TryingHeightCandidateHeightStatus => { - match self.max_height { - Some(max_height) if self.candidate_value > max_height => { - TryingMaxCandidateHeightStatus + InitialCandidateBSizeStatus => TryingBSizeCandidateBSizeStatus, + TryingBSizeCandidateBSizeStatus => { + match self.max_block_size { + Some(max_block_size) if self.candidate_value > max_block_size => { + TryingMaxCandidateBSizeStatus } - _ if self.candidate_value < self.min_height => TryingMinCandidateHeightStatus, - _ => FoundCandidateHeightStatus, + _ if self.candidate_value < self.min_block_size => TryingMinCandidateBSizeStatus, + _ => FoundCandidateBSizeStatus, } } - TryingMaxCandidateHeightStatus => { - if self.candidate_value < self.min_height { - TryingMinCandidateHeightStatus + TryingMaxCandidateBSizeStatus => { + if self.candidate_value < self.min_block_size { + TryingMinCandidateBSizeStatus } else { - FoundCandidateHeightStatus + FoundCandidateBSizeStatus } } - TryingMinCandidateHeightStatus | FoundCandidateHeightStatus => { - FoundCandidateHeightStatus + TryingMinCandidateBSizeStatus | FoundCandidateBSizeStatus => { + FoundCandidateBSizeStatus } }; match self.status { - TryingHeightCandidateHeightStatus => Some((self.height, &mut self.candidate_value)), - TryingMaxCandidateHeightStatus => { - Some((Specified(self.max_height.unwrap()), &mut self.candidate_value)) + TryingBSizeCandidateBSizeStatus => Some((self.block_size, &mut self.candidate_value)), + TryingMaxCandidateBSizeStatus => { + Some((Specified(self.max_block_size.unwrap()), &mut self.candidate_value)) } - TryingMinCandidateHeightStatus => { - Some((Specified(self.min_height), &mut self.candidate_value)) + TryingMinCandidateBSizeStatus => { + Some((Specified(self.min_block_size), &mut self.candidate_value)) } - FoundCandidateHeightStatus => None, - InitialCandidateHeightStatus => fail!(), + FoundCandidateBSizeStatus => None, + InitialCandidateBSizeStatus => fail!(), } } } -enum CandidateHeightIteratorStatus { - InitialCandidateHeightStatus, - TryingHeightCandidateHeightStatus, - TryingMaxCandidateHeightStatus, - TryingMinCandidateHeightStatus, - FoundCandidateHeightStatus, +enum CandidateBSizeIteratorStatus { + InitialCandidateBSizeStatus, + TryingBSizeCandidateBSizeStatus, + TryingMaxCandidateBSizeStatus, + TryingMinCandidateBSizeStatus, + FoundCandidateBSizeStatus, } -// A helper function used in height calculation. -fn translate_including_floats(cur_y: &mut Au, delta: Au, floats: &mut Floats) { - *cur_y = *cur_y + delta; - floats.translate(Point2D(Au(0), -delta)); +// A helper function used in block-size calculation. +fn translate_including_floats(cur_b: &mut Au, delta: Au, floats: &mut Floats) { + *cur_b = *cur_b + delta; + let writing_mode = floats.writing_mode; + floats.translate(LogicalSize::new(writing_mode, Au(0), -delta)); } -/// The real assign-heights traversal for flows with position 'absolute'. +/// The real assign-block-sizes traversal for flows with position 'absolute'. /// /// This is a traversal of an Absolute Flow tree. /// - Relatively positioned flows and the Root flow start new Absolute flow trees. @@ -397,9 +401,9 @@ fn translate_including_floats(cur_y: &mut Au, delta: Au, floats: &mut Floats) { /// /// Note that flows with position 'fixed' just form a flat list as they all /// have the Root flow as their CB. -struct AbsoluteAssignHeightsTraversal<'a>(&'a mut LayoutContext); +struct AbsoluteAssignBSizesTraversal<'a>(&'a mut LayoutContext); -impl<'a> PreorderFlowTraversal for AbsoluteAssignHeightsTraversal<'a> { +impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> { #[inline] fn process(&mut self, flow: &mut Flow) -> bool { let block_flow = flow.as_block(); @@ -411,8 +415,8 @@ impl<'a> PreorderFlowTraversal for AbsoluteAssignHeightsTraversal<'a> { } - let AbsoluteAssignHeightsTraversal(ref ctx) = *self; - block_flow.calculate_abs_height_and_margins(*ctx); + let AbsoluteAssignBSizesTraversal(ref ctx) = *self; + block_flow.calculate_abs_block_size_and_margins(*ctx); true } } @@ -463,7 +467,7 @@ enum FormattingContextType { } // Propagates the `layers_needed_for_descendants` flag appropriately from a child. This is called -// as part of height assignment. +// as part of block-size assignment. // // If any fixed descendants of kids are present, this kid needs a layer. // @@ -499,11 +503,11 @@ pub struct BlockFlow { pub is_root: bool, /// Static y offset of an absolute flow from its CB. - pub static_y_offset: Au, + pub static_b_offset: Au, - /// The width of the last float prior to this block. This is used to speculatively lay out + /// The inline-size of the last float prior to this block. This is used to speculatively lay out /// block formatting contexts. - previous_float_width: Option, + previous_float_inline_size: Option, /// Additional floating flow members. pub float: Option> @@ -515,8 +519,8 @@ impl BlockFlow { base: BaseFlow::new((*node).clone()), fragment: Fragment::new(constructor, node), is_root: false, - static_y_offset: Au::new(0), - previous_float_width: None, + static_b_offset: Au::new(0), + previous_float_inline_size: None, float: None } } @@ -526,8 +530,8 @@ impl BlockFlow { base: BaseFlow::new((*node).clone()), fragment: fragment, is_root: false, - static_y_offset: Au::new(0), - previous_float_width: None, + static_b_offset: Au::new(0), + previous_float_inline_size: None, float: None } } @@ -536,19 +540,20 @@ impl BlockFlow { node: &ThreadSafeLayoutNode, float_kind: FloatKind) -> BlockFlow { + let base = BaseFlow::new((*node).clone()); BlockFlow { - base: BaseFlow::new((*node).clone()), fragment: Fragment::new(constructor, node), is_root: false, - static_y_offset: Au::new(0), - previous_float_width: None, - float: Some(box FloatedBlockInfo::new(float_kind)) + static_b_offset: Au::new(0), + previous_float_inline_size: None, + float: Some(box FloatedBlockInfo::new(float_kind, base.writing_mode)), + base: base, } } /// Return the type of this block. /// - /// This determines the algorithm used to calculate width, height, and the + /// This determines the algorithm used to calculate inline-size, block-size, and the /// relevant margins for this Block. fn block_type(&self) -> BlockType { if self.is_absolutely_positioned() { @@ -572,33 +577,33 @@ impl BlockFlow { } } - /// Compute the used value of width for this Block. - fn compute_used_width(&mut self, ctx: &mut LayoutContext, containing_block_width: Au) { + /// Compute the used value of inline-size for this Block. + fn compute_used_inline_size(&mut self, ctx: &mut LayoutContext, containing_block_inline_size: Au) { let block_type = self.block_type(); match block_type { AbsoluteReplacedType => { - let width_computer = AbsoluteReplaced; - width_computer.compute_used_width(self, ctx, containing_block_width); + let inline_size_computer = AbsoluteReplaced; + inline_size_computer.compute_used_inline_size(self, ctx, containing_block_inline_size); } AbsoluteNonReplacedType => { - let width_computer = AbsoluteNonReplaced; - width_computer.compute_used_width(self, ctx, containing_block_width); + let inline_size_computer = AbsoluteNonReplaced; + inline_size_computer.compute_used_inline_size(self, ctx, containing_block_inline_size); } FloatReplacedType => { - let width_computer = FloatReplaced; - width_computer.compute_used_width(self, ctx, containing_block_width); + let inline_size_computer = FloatReplaced; + inline_size_computer.compute_used_inline_size(self, ctx, containing_block_inline_size); } FloatNonReplacedType => { - let width_computer = FloatNonReplaced; - width_computer.compute_used_width(self, ctx, containing_block_width); + let inline_size_computer = FloatNonReplaced; + inline_size_computer.compute_used_inline_size(self, ctx, containing_block_inline_size); } BlockReplacedType => { - let width_computer = BlockReplaced; - width_computer.compute_used_width(self, ctx, containing_block_width); + let inline_size_computer = BlockReplaced; + inline_size_computer.compute_used_inline_size(self, ctx, containing_block_inline_size); } BlockNonReplacedType => { - let width_computer = BlockNonReplaced; - width_computer.compute_used_width(self, ctx, containing_block_width); + let inline_size_computer = BlockNonReplaced; + inline_size_computer.compute_used_inline_size(self, ctx, containing_block_inline_size); } } } @@ -609,11 +614,11 @@ impl BlockFlow { } /// Return the static x offset from the appropriate Containing Block for this flow. - pub fn static_x_offset(&self) -> Au { + pub fn static_i_offset(&self) -> Au { if self.is_fixed() { - self.base.fixed_static_x_offset + self.base.fixed_static_i_offset } else { - self.base.absolute_static_x_offset + self.base.absolute_static_i_offset } } @@ -624,11 +629,11 @@ impl BlockFlow { /// Note: Assume this is called in a top-down traversal, so it is ok to /// reference the CB. #[inline] - pub fn containing_block_size(&mut self, viewport_size: Size2D) -> Size2D { + pub fn containing_block_size(&mut self, viewport_size: Size2D) -> LogicalSize { assert!(self.is_absolutely_positioned()); if self.is_fixed() { // Initial containing block is the CB for the root - viewport_size + LogicalSize::from_physical(self.base.writing_mode, viewport_size) } else { self.base.absolute_cb.generated_containing_block_rect().size } @@ -639,7 +644,7 @@ impl BlockFlow { /// Traverse all your direct absolute descendants, who will then traverse /// their direct absolute descendants. /// Also, set the static y offsets for each descendant (using the value - /// which was bubbled up during normal assign-height). + /// which was bubbled up during normal assign-block-size). /// /// Return true if the traversal is to continue or false to stop. fn traverse_preorder_absolute_flows(&mut self, @@ -654,14 +659,14 @@ impl BlockFlow { return false } - let cb_top_edge_offset = flow.generated_containing_block_rect().origin.y; + let cb_block_start_edge_offset = flow.generated_containing_block_rect().start.b; let mut descendant_offset_iter = mut_base(flow).abs_descendants.iter_with_offset(); // Pass in the respective static y offset for each descendant. for (ref mut descendant_link, ref y_offset) in descendant_offset_iter { let block = descendant_link.as_block(); // The stored y_offset is wrt to the flow box. // Translate it to the CB (which is the padding box). - block.static_y_offset = **y_offset - cb_top_edge_offset; + block.static_b_offset = **y_offset - cb_block_start_edge_offset; if !block.traverse_preorder_absolute_flows(traversal) { return false } @@ -702,13 +707,13 @@ impl BlockFlow { } } - /// Return shrink-to-fit width. + /// Return shrink-to-fit inline-size. /// - /// This is where we use the preferred widths and minimum widths - /// calculated in the bubble-widths traversal. - fn get_shrink_to_fit_width(&self, available_width: Au) -> Au { - geometry::min(self.base.intrinsic_widths.preferred_width, - geometry::max(self.base.intrinsic_widths.minimum_width, available_width)) + /// This is where we use the preferred inline-sizes and minimum inline-sizes + /// calculated in the bubble-inline-sizes traversal. + fn get_shrink_to_fit_inline_size(&self, available_inline_size: Au) -> Au { + geometry::min(self.base.intrinsic_inline_sizes.preferred_inline_size, + geometry::max(self.base.intrinsic_inline_sizes.minimum_inline_size, available_inline_size)) } /// Collect and update static y-offsets bubbled up by kids. @@ -717,10 +722,10 @@ impl BlockFlow { /// direct descendants and all fixed descendants, in tree order. /// /// Assume that this is called in a bottom-up traversal (specifically, the - /// assign-height traversal). So, kids have their flow origin already set. + /// assign-block-size traversal). So, kids have their flow origin already set. /// In the case of absolute flow kids, they have their hypothetical box /// position already set. - fn collect_static_y_offsets_from_kids(&mut self) { + fn collect_static_b_offsets_from_kids(&mut self) { let mut abs_descendant_y_offsets = Vec::new(); for kid in self.base.child_iter() { let mut gives_abs_offsets = true; @@ -731,7 +736,7 @@ impl BlockFlow { // would be the CB for them. gives_abs_offsets = false; // Give the offset for the current absolute flow alone. - abs_descendant_y_offsets.push(kid_block.get_hypothetical_top_edge()); + abs_descendant_y_offsets.push(kid_block.get_hypothetical_block_start_edge()); } else if kid_block.is_positioned() { // It won't contribute any offsets because it would be the CB // for the descendants. @@ -742,15 +747,15 @@ impl BlockFlow { if gives_abs_offsets { let kid_base = flow::mut_base(kid); // Avoid copying the offset vector. - let offsets = mem::replace(&mut kid_base.abs_descendants.static_y_offsets, Vec::new()); + let offsets = mem::replace(&mut kid_base.abs_descendants.static_b_offsets, Vec::new()); // Consume all the static y-offsets bubbled up by kid. for y_offset in offsets.move_iter() { // The offsets are wrt the kid flow box. Translate them to current flow. - abs_descendant_y_offsets.push(y_offset + kid_base.position.origin.y); + abs_descendant_y_offsets.push(y_offset + kid_base.position.start.b); } } } - self.base.abs_descendants.static_y_offsets = abs_descendant_y_offsets; + self.base.abs_descendants.static_b_offsets = abs_descendant_y_offsets; } /// If this is the root flow, shifts all kids down and adjusts our size to account for @@ -763,80 +768,81 @@ impl BlockFlow { return } - let (top_margin_value, bottom_margin_value) = match self.base.collapsible_margins { + let (block_start_margin_value, block_end_margin_value) = match self.base.collapsible_margins { MarginsCollapseThrough(margin) => (Au(0), margin.collapse()), - MarginsCollapse(top_margin, bottom_margin) => { - (top_margin.collapse(), bottom_margin.collapse()) + MarginsCollapse(block_start_margin, block_end_margin) => { + (block_start_margin.collapse(), block_end_margin.collapse()) } - NoCollapsibleMargins(top, bottom) => (top, bottom), + NoCollapsibleMargins(block_start, block_end) => (block_start, block_end), }; // Shift all kids down (or up, if margins are negative) if necessary. - if top_margin_value != Au(0) { + if block_start_margin_value != Au(0) { for kid in self.base.child_iter() { let kid_base = flow::mut_base(kid); - kid_base.position.origin.y = kid_base.position.origin.y + top_margin_value + kid_base.position.start.b = kid_base.position.start.b + block_start_margin_value } } - self.base.position.size.height = self.base.position.size.height + top_margin_value + - bottom_margin_value; - self.fragment.border_box.size.height = self.fragment.border_box.size.height + top_margin_value + - bottom_margin_value; + self.base.position.size.block = self.base.position.size.block + block_start_margin_value + + block_end_margin_value; + self.fragment.border_box.size.block = self.fragment.border_box.size.block + block_start_margin_value + + block_end_margin_value; } - /// Assign height for current flow. + /// Assign block-size for current flow. /// /// * Collapse margins for flow's children and set in-flow child flows' y-coordinates now that - /// we know their heights. - /// * Calculate and set the height of the current flow. - /// * Calculate height, vertical margins, and y-coordinate for the flow's box. Ideally, this + /// we know their block-sizes. + /// * Calculate and set the block-size of the current flow. + /// * Calculate block-size, vertical margins, and y-coordinate for the flow's box. Ideally, this /// should be calculated using CSS § 10.6.7. /// - /// For absolute flows, we store the calculated content height for the flow. We defer the + /// For absolute flows, we store the calculated content block-size for the flow. We defer the /// calculation of the other values until a later traversal. /// /// `inline(always)` because this is only ever called by in-order or non-in-order top-level /// methods #[inline(always)] - pub fn assign_height_block_base(&mut self, + pub fn assign_block_size_block_base(&mut self, layout_context: &mut LayoutContext, margins_may_collapse: MarginsMayCollapseFlag) { // Our current border-box position. - let mut cur_y = Au(0); + let mut cur_b = Au(0); // Absolute positioning establishes a block formatting context. Don't propagate floats // in or out. (But do propagate them between kids.) if self.is_absolutely_positioned() { - self.base.floats = Floats::new(); + self.base.floats = Floats::new(self.fragment.style.writing_mode); } if margins_may_collapse != MarginsMayCollapse { - self.base.floats = Floats::new(); + self.base.floats = Floats::new(self.fragment.style.writing_mode); } let mut margin_collapse_info = MarginCollapseInfo::new(); - self.base.floats.translate(Point2D(-self.fragment.left_offset(), Au(0))); + self.base.floats.translate(LogicalSize::new( + self.fragment.style.writing_mode, -self.fragment.inline_start_offset(), Au(0))); - // The sum of our top border and top padding. - let top_offset = self.fragment.border_padding.top; - translate_including_floats(&mut cur_y, top_offset, &mut self.base.floats); + // The sum of our block-start border and block-start padding. + let block_start_offset = self.fragment.border_padding.block_start; + translate_including_floats(&mut cur_b, block_start_offset, &mut self.base.floats); - let can_collapse_top_margin_with_kids = + let can_collapse_block_start_margin_with_kids = margins_may_collapse == MarginsMayCollapse && !self.is_absolutely_positioned() && - self.fragment.border_padding.top == Au(0); - margin_collapse_info.initialize_top_margin(&self.fragment, - can_collapse_top_margin_with_kids); + self.fragment.border_padding.block_start == Au(0); + margin_collapse_info.initialize_block_start_margin(&self.fragment, + can_collapse_block_start_margin_with_kids); - // At this point, `cur_y` is at the content edge of our box. Now iterate over children. + // At this point, `cur_b` is at the content edge of our box. Now iterate over children. let mut floats = self.base.floats.clone(); let mut layers_needed_for_descendants = false; for kid in self.base.child_iter() { if kid.is_absolutely_positioned() { // Assume that the *hypothetical box* for an absolute flow starts immediately after - // the bottom border edge of the previous flow. - flow::mut_base(kid).position.origin.y = cur_y; - kid.assign_height_for_inorder_child_if_necessary(layout_context); + // the block-end border edge of the previous flow. + flow::mut_base(kid).position.start.b = cur_b; + kid.assign_block_size_for_inorder_child_if_necessary(layout_context); propagate_layer_flag_from_child(&mut layers_needed_for_descendants, kid); // Skip the collapsing and float processing for absolute flow kids and continue @@ -844,21 +850,21 @@ impl BlockFlow { continue } - // Assign height now for the child if it was impacted by floats and we couldn't before. + // Assign block-size now for the child if it was impacted by floats and we couldn't before. flow::mut_base(kid).floats = floats.clone(); if kid.is_float() { - // FIXME(pcwalton): Using `position.origin.y` to mean the float ceiling is a + // FIXME(pcwalton): Using `position.start.b` to mean the float ceiling is a // bit of a hack. - flow::mut_base(kid).position.origin.y = + flow::mut_base(kid).position.start.b = margin_collapse_info.current_float_ceiling(); propagate_layer_flag_from_child(&mut layers_needed_for_descendants, kid); let kid_was_impacted_by_floats = - kid.assign_height_for_inorder_child_if_necessary(layout_context); + kid.assign_block_size_for_inorder_child_if_necessary(layout_context); assert!(kid_was_impacted_by_floats); // As it was a float itself... let kid_base = flow::mut_base(kid); - kid_base.position.origin.y = cur_y; + kid_base.position.start.b = cur_b; floats = kid_base.floats.clone(); continue } @@ -872,20 +878,20 @@ impl BlockFlow { // in this rare case. (Note that WebKit can lay blocks out twice; this may be related, // although I haven't looked into it closely.) if kid.float_clearance() != clear::none { - flow::mut_base(kid).floats = Floats::new() + flow::mut_base(kid).floats = Floats::new(self.fragment.style.writing_mode) } // Lay the child out if this was an in-order traversal. let kid_was_impacted_by_floats = - kid.assign_height_for_inorder_child_if_necessary(layout_context); + kid.assign_block_size_for_inorder_child_if_necessary(layout_context); // Mark flows for layerization if necessary to handle painting order correctly. propagate_layer_flag_from_child(&mut layers_needed_for_descendants, kid); // Handle any (possibly collapsed) top margin. - let delta = - margin_collapse_info.advance_top_margin(&flow::base(kid).collapsible_margins); - translate_including_floats(&mut cur_y, delta, &mut floats); + let delta = margin_collapse_info.advance_block_start_margin( + &flow::base(kid).collapsible_margins); + translate_including_floats(&mut cur_b, delta, &mut floats); // Clear past the floats that came in, if necessary. let clearance = match kid.float_clearance() { @@ -894,13 +900,13 @@ impl BlockFlow { clear::right => floats.clearance(ClearRight), clear::both => floats.clearance(ClearBoth), }; - cur_y = cur_y + clearance; + cur_b = cur_b + clearance; - // At this point, `cur_y` is at the border edge of the child. - flow::mut_base(kid).position.origin.y = cur_y; + // At this point, `cur_b` is at the border edge of the child. + flow::mut_base(kid).position.start.b = cur_b; // Now pull out the child's outgoing floats. We didn't do this immediately after the - // `assign_height_for_inorder_child_if_necessary` call because clearance on a block + // `assign_block-size_for_inorder_child_if_necessary` call because clearance on a block // operates on the floats that come *in*, not the floats that go *out*. if kid_was_impacted_by_floats { floats = flow::mut_base(kid).floats.clone() @@ -909,11 +915,11 @@ impl BlockFlow { // Move past the child's border box. Do not use the `translate_including_floats` // function here because the child has already translated floats past its border box. let kid_base = flow::mut_base(kid); - cur_y = cur_y + kid_base.position.size.height; + cur_b = cur_b + kid_base.position.size.block; - // Handle any (possibly collapsed) bottom margin. - let delta = margin_collapse_info.advance_bottom_margin(&kid_base.collapsible_margins); - translate_including_floats(&mut cur_y, delta, &mut floats); + // Handle any (possibly collapsed) block-end margin. + let delta = margin_collapse_info.advance_block_end_margin(&kid_base.collapsible_margins); + translate_including_floats(&mut cur_b, delta, &mut floats); } // Mark ourselves for layerization if that will be necessary to paint in the proper order @@ -921,77 +927,79 @@ impl BlockFlow { self.base.flags.set_layers_needed_for_descendants(layers_needed_for_descendants); // Collect various offsets needed by absolutely positioned descendants. - self.collect_static_y_offsets_from_kids(); + self.collect_static_b_offsets_from_kids(); - // Add in our bottom margin and compute our collapsible margins. - let can_collapse_bottom_margin_with_kids = + // Add in our block-end margin and compute our collapsible margins. + let can_collapse_block_end_margin_with_kids = margins_may_collapse == MarginsMayCollapse && !self.is_absolutely_positioned() && - self.fragment.border_padding.bottom == Au(0); + self.fragment.border_padding.block_end == Au(0); let (collapsible_margins, delta) = margin_collapse_info.finish_and_compute_collapsible_margins( &self.fragment, - can_collapse_bottom_margin_with_kids); + can_collapse_block_end_margin_with_kids); self.base.collapsible_margins = collapsible_margins; - translate_including_floats(&mut cur_y, delta, &mut floats); + translate_including_floats(&mut cur_b, delta, &mut floats); // FIXME(#2003, pcwalton): The max is taken here so that you can scroll the page, but this // is not correct behavior according to CSS 2.1 § 10.5. Instead I think we should treat the // root element as having `overflow: scroll` and use the layers-based scrolling // infrastructure to make it scrollable. - let mut height = cur_y - top_offset; + let mut block_size = cur_b - block_start_offset; if self.is_root() { - height = Au::max(layout_context.screen_size.height, height) + let screen_size = LogicalSize::from_physical( + self.fragment.style.writing_mode, layout_context.screen_size); + block_size = Au::max(screen_size.block, block_size) } if self.is_absolutely_positioned() { - // The content height includes all the floats per CSS 2.1 § 10.6.7. The easiest way to + // The content block-size includes all the floats per CSS 2.1 § 10.6.7. The easiest way to // handle this is to just treat this as clearance. - height = height + floats.clearance(ClearBoth); + block_size = block_size + floats.clearance(ClearBoth); // Fixed position layers get layers. if self.is_fixed() { self.base.flags.set_needs_layer(true) } - // Store the content height for use in calculating the absolute flow's dimensions + // Store the content block-size for use in calculating the absolute flow's dimensions // later. - self.fragment.border_box.size.height = height; + self.fragment.border_box.size.block = block_size; return } - let mut candidate_height_iterator = CandidateHeightIterator::new(self.fragment.style(), + let mut candidate_block_size_iterator = CandidateBSizeIterator::new(self.fragment.style(), None); - for (candidate_height, new_candidate_height) in candidate_height_iterator { - *new_candidate_height = match candidate_height { - Auto => height, + for (candidate_block_size, new_candidate_block_size) in candidate_block_size_iterator { + *new_candidate_block_size = match candidate_block_size { + Auto => block_size, Specified(value) => value } } - // Adjust `cur_y` as necessary to account for the explicitly-specified height. - height = candidate_height_iterator.candidate_value; - let delta = height - (cur_y - top_offset); - translate_including_floats(&mut cur_y, delta, &mut floats); + // Adjust `cur_b` as necessary to account for the explicitly-specified block-size. + block_size = candidate_block_size_iterator.candidate_value; + let delta = block_size - (cur_b - block_start_offset); + translate_including_floats(&mut cur_b, delta, &mut floats); - // Compute content height and noncontent height. - let bottom_offset = self.fragment.border_padding.bottom; - translate_including_floats(&mut cur_y, bottom_offset, &mut floats); + // Compute content block-size and noncontent block-size. + let block_end_offset = self.fragment.border_padding.block_end; + translate_including_floats(&mut cur_b, block_end_offset, &mut floats); - // Now that `cur_y` is at the bottom of the border box, compute the final border box + // Now that `cur_b` is at the block-end of the border box, compute the final border box // position. - self.fragment.border_box.size.height = cur_y; - self.fragment.border_box.origin.y = Au(0); - self.base.position.size.height = cur_y; + self.fragment.border_box.size.block = cur_b; + self.fragment.border_box.start.b = Au(0); + self.base.position.size.block = cur_b; self.base.floats = floats.clone(); self.adjust_fragments_for_collapsed_margins_if_root(); if self.is_root_of_absolute_flow_tree() { - // Assign heights for all flows in this Absolute flow tree. - // This is preorder because the height of an absolute flow may depend on - // the height of its CB, which may also be an absolute flow. - self.traverse_preorder_absolute_flows(&mut AbsoluteAssignHeightsTraversal( + // Assign block-sizes for all flows in this Absolute flow tree. + // This is preorder because the block-size of an absolute flow may depend on + // the block-size of its CB, which may also be an absolute flow. + self.traverse_preorder_absolute_flows(&mut AbsoluteAssignBSizesTraversal( layout_context)); // Store overflow for all absolute descendants. self.traverse_postorder_absolute_flows(&mut AbsoluteStoreOverflowTraversal { @@ -1007,23 +1015,25 @@ impl BlockFlow { /// This does not give any information about any float descendants because they do not affect /// elements outside of the subtree rooted at this float. /// - /// This function is called on a kid flow by a parent. Therefore, `assign_height_float` was + /// This function is called on a kid flow by a parent. Therefore, `assign_block-size_float` was /// already called on this kid flow by the traversal function. So, the values used are /// well-defined. pub fn place_float(&mut self) { - let height = self.fragment.border_box.size.height; + let block_size = self.fragment.border_box.size.block; let clearance = match self.fragment.clear() { None => Au(0), Some(clear) => self.base.floats.clearance(clear), }; - let margin_height = self.fragment.margin.vertical(); + let margin_block_size = self.fragment.margin.block_start_end(); let info = PlacementInfo { - size: Size2D(self.base.position.size.width + self.fragment.margin.horizontal() + - self.fragment.border_padding.horizontal(), - height + margin_height), - ceiling: clearance + self.base.position.origin.y, - max_width: self.float.get_ref().containing_width, + size: LogicalSize::new( + self.fragment.style.writing_mode, + self.base.position.size.inline + self.fragment.margin.inline_start_end() + + self.fragment.border_padding.inline_start_end(), + block_size + margin_block_size), + ceiling: clearance + self.base.position.start.b, + max_inline_size: self.float.get_ref().containing_inline_size, kind: self.float.get_ref().float_kind, }; @@ -1034,62 +1044,64 @@ impl BlockFlow { self.float.get_mut_ref().rel_pos = self.base.floats.last_float_pos().unwrap(); } - /// Assign height for current flow. + /// Assign block-size for current flow. /// /// + Set in-flow child flows' y-coordinates now that we know their - /// heights. This _doesn't_ do any margin collapsing for its children. - /// + Calculate height and y-coordinate for the flow's box. Ideally, this + /// block-sizes. This _doesn't_ do any margin collapsing for its children. + /// + Calculate block-size and y-coordinate for the flow's box. Ideally, this /// should be calculated using CSS Section 10.6.7 /// - /// It does not calculate the height of the flow itself. - pub fn assign_height_float(&mut self, ctx: &mut LayoutContext) { - let mut floats = Floats::new(); + /// It does not calculate the block-size of the flow itself. + pub fn assign_block_size_float(&mut self, ctx: &mut LayoutContext) { + let mut floats = Floats::new(self.fragment.style.writing_mode); for kid in self.base.child_iter() { flow::mut_base(kid).floats = floats.clone(); - kid.assign_height_for_inorder_child_if_necessary(ctx); + kid.assign_block_size_for_inorder_child_if_necessary(ctx); floats = flow::mut_base(kid).floats.clone(); } - let top_offset = self.fragment.margin.top + self.fragment.border_padding.top; - let mut cur_y = top_offset; + let block_start_offset = self.fragment.margin.block_start + self.fragment.border_padding.block_start; + let mut cur_b = block_start_offset; - // cur_y is now at the top content edge + // cur_b is now at the block-start content edge for kid in self.base.child_iter() { let child_base = flow::mut_base(kid); - child_base.position.origin.y = cur_y; - // cur_y is now at the bottom margin edge of kid - cur_y = cur_y + child_base.position.size.height; + child_base.position.start.b = cur_b; + // cur_b is now at the block-end margin edge of kid + cur_b = cur_b + child_base.position.size.block; } // Intrinsic height should include floating descendants with a margin // below the element's bottom edge (see CSS Section 10.6.7). - let content_height = geometry::max(cur_y - top_offset, floats.clearance(ClearBoth)); + let content_block_size = geometry::max( + cur_b - block_start_offset, + floats.clearance(ClearBoth)); // Floats establish a block formatting context, so we discard the output floats here. drop(floats); // The associated fragment has the border box of this flow. - self.fragment.border_box.origin.y = self.fragment.margin.top; + self.fragment.border_box.start.b = self.fragment.margin.block_start; - // Calculate content height, taking `min-height` and `max-height` into account. - let mut candidate_height_iterator = CandidateHeightIterator::new(self.fragment.style(), None); - for (candidate_height, new_candidate_height) in candidate_height_iterator { - *new_candidate_height = match candidate_height { - Auto => content_height, + // Calculate content block-size, taking `min-block-size` and `max-block-size` into account. + let mut candidate_block_size_iterator = CandidateBSizeIterator::new(self.fragment.style(), None); + for (candidate_block_size, new_candidate_block_size) in candidate_block_size_iterator { + *new_candidate_block_size = match candidate_block_size { + Auto => content_block_size, Specified(value) => value, } } - let content_height = candidate_height_iterator.candidate_value; - let noncontent_height = self.fragment.border_padding.vertical(); - debug!("assign_height_float -- height: {}", content_height + noncontent_height); - self.fragment.border_box.size.height = content_height + noncontent_height; + let content_block_size = candidate_block_size_iterator.candidate_value; + let noncontent_block_size = self.fragment.border_padding.block_start_end(); + debug!("assign_block_size_float -- block_size: {}", content_block_size + noncontent_block_size); + self.fragment.border_box.size.block = content_block_size + noncontent_block_size; } fn build_display_list_block_common(&mut self, layout_context: &LayoutContext, - offset: Point2D, + offset: LogicalPoint, background_border_level: BackgroundAndBorderLevel) { let rel_offset = self.fragment.relative_position(&self.base @@ -1102,7 +1114,9 @@ impl BlockFlow { let mut accumulator = self.fragment.build_display_list(&mut display_list, layout_context, - self.base.abs_position + rel_offset + offset, + self.base.abs_position + .add_point(&offset) + + rel_offset, background_border_level, None); @@ -1141,7 +1155,9 @@ impl BlockFlow { } else if self.is_absolutely_positioned() { self.build_display_list_abs(layout_context) } else { - self.build_display_list_block_common(layout_context, Zero::zero(), BlockLevel) + let writing_mode = self.base.writing_mode; + self.build_display_list_block_common( + layout_context, LogicalPoint::zero(writing_mode), BlockLevel) } } @@ -1154,96 +1170,98 @@ impl BlockFlow { DisplayList::new()).flatten(FloatStackingLevel) } - /// Calculate and set the height, offsets, etc. for absolutely positioned flow. + /// Calculate and set the block-size, offsets, etc. for absolutely positioned flow. /// /// The layout for its in-flow children has been done during normal layout. /// This is just the calculation of: - /// + height for the flow + /// + block-size for the flow /// + y-coordinate of the flow wrt its Containing Block. - /// + height, vertical margins, and y-coordinate for the flow's box. - fn calculate_abs_height_and_margins(&mut self, ctx: &LayoutContext) { - let containing_block_height = self.containing_block_size(ctx.screen_size).height; - let static_y_offset = self.static_y_offset; + /// + block-size, vertical margins, and y-coordinate for the flow's box. + fn calculate_abs_block_size_and_margins(&mut self, ctx: &LayoutContext) { + let containing_block_block_size = self.containing_block_size(ctx.screen_size).block; + let static_b_offset = self.static_b_offset; - // This is the stored content height value from assign-height - let content_height = self.fragment.content_box().size.height; + // This is the stored content block-size value from assign-block-size + let content_block_size = self.fragment.content_box().size.block; let mut solution = None; { - // Non-auto margin-top and margin-bottom values have already been - // calculated during assign-width. - let margin_top = match self.fragment.style().get_margin().margin_top { + // Non-auto margin-block-start and margin-block-end values have already been + // calculated during assign-inline-size. + let margin = self.fragment.style().logical_margin(); + let margin_block_start = match margin.block_start { LPA_Auto => Auto, - _ => Specified(self.fragment.margin.top) + _ => Specified(self.fragment.margin.block_start) }; - let margin_bottom = match self.fragment.style().get_margin().margin_bottom { + let margin_block_end = match margin.block_end { LPA_Auto => Auto, - _ => Specified(self.fragment.margin.bottom) + _ => Specified(self.fragment.margin.block_end) }; - let top; - let bottom; + let block_start; + let block_end; { - let position_style = self.fragment.style().get_positionoffsets(); - top = MaybeAuto::from_style(position_style.top, containing_block_height); - bottom = MaybeAuto::from_style(position_style.bottom, containing_block_height); + let position = self.fragment.style().logical_position(); + block_start = MaybeAuto::from_style(position.block_start, containing_block_block_size); + block_end = MaybeAuto::from_style(position.block_end, containing_block_block_size); } - let available_height = containing_block_height - self.fragment.border_padding.vertical(); + let available_block_size = containing_block_block_size - self.fragment.border_padding.block_start_end(); if self.is_replaced_content() { - // Calculate used value of height just like we do for inline replaced elements. - // TODO: Pass in the containing block height when Fragment's - // assign-height can handle it correctly. - self.fragment.assign_replaced_height_if_necessary(); - // TODO: Right now, this content height value includes the - // margin because of erroneous height calculation in fragment. + // Calculate used value of block-size just like we do for inline replaced elements. + // TODO: Pass in the containing block block-size when Fragment's + // assign-block-size can handle it correctly. + self.fragment.assign_replaced_block_size_if_necessary(); + // TODO: Right now, this content block-size value includes the + // margin because of erroneous block-size calculation in fragment. // Check this when that has been fixed. - let height_used_val = self.fragment.border_box.size.height; - solution = Some(HeightConstraintSolution::solve_vertical_constraints_abs_replaced( - height_used_val, - margin_top, - margin_bottom, - top, - bottom, - content_height, - available_height, - static_y_offset)); + let block_size_used_val = self.fragment.border_box.size.block; + solution = Some(BSizeConstraintSolution::solve_vertical_constraints_abs_replaced( + block_size_used_val, + margin_block_start, + margin_block_end, + block_start, + block_end, + content_block_size, + available_block_size, + static_b_offset)); } else { let style = self.fragment.style(); - let mut candidate_height_iterator = - CandidateHeightIterator::new(style, Some(containing_block_height)); + let mut candidate_block_size_iterator = + CandidateBSizeIterator::new(style, Some(containing_block_block_size)); - for (height_used_val, new_candidate_height) in candidate_height_iterator { + for (block_size_used_val, new_candidate_block_size) in candidate_block_size_iterator { solution = - Some(HeightConstraintSolution::solve_vertical_constraints_abs_nonreplaced( - height_used_val, - margin_top, - margin_bottom, - top, - bottom, - content_height, - available_height, - static_y_offset)); + Some(BSizeConstraintSolution::solve_vertical_constraints_abs_nonreplaced( + block_size_used_val, + margin_block_start, + margin_block_end, + block_start, + block_end, + content_block_size, + available_block_size, + static_b_offset)); - *new_candidate_height = solution.unwrap().height + *new_candidate_block_size = solution.unwrap().block_size } } } let solution = solution.unwrap(); - self.fragment.margin.top = solution.margin_top; - self.fragment.margin.bottom = solution.margin_bottom; - self.fragment.border_box.origin.y = Au(0); - self.fragment.border_box.size.height = solution.height + self.fragment.border_padding.vertical(); + self.fragment.margin.block_start = solution.margin_block_start; + self.fragment.margin.block_end = solution.margin_block_end; + self.fragment.border_box.start.b = Au(0); + self.fragment.border_box.size.block = solution.block_size + self.fragment.border_padding.block_start_end(); - self.base.position.origin.y = solution.top + self.fragment.margin.top; - self.base.position.size.height = solution.height + self.fragment.border_padding.vertical(); + self.base.position.start.b = solution.block_start + self.fragment.margin.block_start; + self.base.position.size.block = solution.block_size + self.fragment.border_padding.block_start_end(); } /// Add display items for Absolutely Positioned flow. fn build_display_list_abs(&mut self, layout_context: &LayoutContext) { + let writing_mode = self.base.writing_mode; self.build_display_list_block_common(layout_context, - Zero::zero(), + LogicalPoint::zero(writing_mode), RootOfStackingContextLevel); if !self.base.absolute_position_info.layers_needed_for_positioned_flows && @@ -1259,10 +1277,10 @@ impl BlockFlow { // If we got here, then we need a new layer. let layer_rect = self.base.position.union(&self.base.overflow); - let size = Size2D(layer_rect.size.width.to_nearest_px() as uint, - layer_rect.size.height.to_nearest_px() as uint); - let origin = Point2D(layer_rect.origin.x.to_nearest_px() as uint, - layer_rect.origin.y.to_nearest_px() as uint); + let size = Size2D(layer_rect.size.inline.to_nearest_px() as uint, + layer_rect.size.block.to_nearest_px() as uint); + let origin = Point2D(layer_rect.start.i.to_nearest_px() as uint, + layer_rect.start.b.to_nearest_px() as uint); let scroll_policy = if self.is_fixed() { FixedPosition } else { @@ -1279,99 +1297,100 @@ impl BlockFlow { self.base.layers.push_back(new_layer) } - /// Return the top outer edge of the hypothetical box for an absolute flow. + /// Return the block-start outer edge of the hypothetical box for an absolute flow. /// /// This is wrt its parent flow box. /// - /// During normal layout assign-height, the absolute flow's position is + /// During normal layout assign-block-size, the absolute flow's position is /// roughly set to its static position (the position it would have had in /// the normal flow). - fn get_hypothetical_top_edge(&self) -> Au { - self.base.position.origin.y + fn get_hypothetical_block_start_edge(&self) -> Au { + self.base.position.start.b } - /// Assigns the computed left content edge and width to all the children of this block flow. + /// Assigns the computed inline-start content edge and inline-size to all the children of this block flow. /// Also computes whether each child will be impacted by floats. /// - /// `#[inline(always)]` because this is called only from block or table width assignment and + /// `#[inline(always)]` because this is called only from block or table inline-size assignment and /// the code for block layout is significantly simpler. #[inline(always)] - pub fn propagate_assigned_width_to_children(&mut self, - left_content_edge: Au, - content_width: Au, - opt_col_widths: Option>) { + pub fn propagate_assigned_inline_size_to_children(&mut self, + inline_start_content_edge: Au, + content_inline_size: Au, + opt_col_inline_sizes: Option>) { // Keep track of whether floats could impact each child. - let mut left_floats_impact_child = self.base.flags.impacted_by_left_floats(); - let mut right_floats_impact_child = self.base.flags.impacted_by_right_floats(); + let mut inline_start_floats_impact_child = self.base.flags.impacted_by_left_floats(); + let mut inline_end_floats_impact_child = self.base.flags.impacted_by_right_floats(); - let absolute_static_x_offset = if self.is_positioned() { - // This flow is the containing block. The static X offset will be the left padding + let absolute_static_i_offset = if self.is_positioned() { + // This flow is the containing block. The static X offset will be the inline-start padding // edge. - self.fragment.border_padding.left - model::border_from_style(self.fragment.style()).left + self.fragment.border_padding.inline_start + - self.fragment.style().logical_border_width().inline_start } else { - // For kids, the left margin edge will be at our left content edge. The current static - // offset is at our left margin edge. So move in to the left content edge. - self.base.absolute_static_x_offset + left_content_edge + // For kids, the inline-start margin edge will be at our inline-start content edge. The current static + // offset is at our inline-start margin edge. So move in to the inline-start content edge. + self.base.absolute_static_i_offset + inline_start_content_edge }; - let fixed_static_x_offset = self.base.fixed_static_x_offset + left_content_edge; + let fixed_static_i_offset = self.base.fixed_static_i_offset + inline_start_content_edge; let flags = self.base.flags.clone(); // This value is used only for table cells. - let mut left_margin_edge = left_content_edge; + let mut inline_start_margin_edge = inline_start_content_edge; - // The width of the last float, if there was one. This is used for estimating the widths of - // block formatting contexts. (We estimate that the width of any block formatting context - // that we see will be based on the width of the containing block as well as the last float + // The inline-size of the last float, if there was one. This is used for estimating the inline-sizes of + // block formatting contexts. (We estimate that the inline-size of any block formatting context + // that we see will be based on the inline-size of the containing block as well as the last float // seen before it.) - let mut last_float_width = None; + let mut last_float_inline_size = None; for (i, kid) in self.base.child_iter().enumerate() { if kid.is_block_flow() { let kid_block = kid.as_block(); - kid_block.base.absolute_static_x_offset = absolute_static_x_offset; - kid_block.base.fixed_static_x_offset = fixed_static_x_offset; + kid_block.base.absolute_static_i_offset = absolute_static_i_offset; + kid_block.base.fixed_static_i_offset = fixed_static_i_offset; if kid_block.is_float() { - last_float_width = Some(kid_block.base.intrinsic_widths.preferred_width) + last_float_inline_size = Some(kid_block.base.intrinsic_inline_sizes.preferred_inline_size) } else { - kid_block.previous_float_width = last_float_width + kid_block.previous_float_inline_size = last_float_inline_size } } - // The left margin edge of the child flow is at our left content edge, and its width - // is our content width. - flow::mut_base(kid).position.origin.x = left_content_edge; - flow::mut_base(kid).position.size.width = content_width; + // The inline-start margin edge of the child flow is at our inline-start content edge, and its inline-size + // is our content inline-size. + flow::mut_base(kid).position.start.i = inline_start_content_edge; + flow::mut_base(kid).position.size.inline = content_inline_size; // Determine float impaction. match kid.float_clearance() { clear::none => {} - clear::left => left_floats_impact_child = false, - clear::right => right_floats_impact_child = false, + clear::left => inline_start_floats_impact_child = false, + clear::right => inline_end_floats_impact_child = false, clear::both => { - left_floats_impact_child = false; - right_floats_impact_child = false; + inline_start_floats_impact_child = false; + inline_end_floats_impact_child = false; } } { let kid_base = flow::mut_base(kid); - left_floats_impact_child = left_floats_impact_child || + inline_start_floats_impact_child = inline_start_floats_impact_child || kid_base.flags.has_left_floated_descendants(); - right_floats_impact_child = right_floats_impact_child || + inline_end_floats_impact_child = inline_end_floats_impact_child || kid_base.flags.has_right_floated_descendants(); - kid_base.flags.set_impacted_by_left_floats(left_floats_impact_child); - kid_base.flags.set_impacted_by_right_floats(right_floats_impact_child); + kid_base.flags.set_impacted_by_left_floats(inline_start_floats_impact_child); + kid_base.flags.set_impacted_by_right_floats(inline_end_floats_impact_child); } // Handle tables. - match opt_col_widths { - Some(ref col_widths) => { - propagate_column_widths_to_child(kid, + match opt_col_inline_sizes { + Some(ref col_inline_sizes) => { + propagate_column_inline_sizes_to_child(kid, i, - content_width, - col_widths.as_slice(), - &mut left_margin_edge) + content_inline_size, + col_inline_sizes.as_slice(), + &mut inline_start_margin_edge) } None => {} } @@ -1417,44 +1436,44 @@ impl Flow for BlockFlow { self.fragment.style().get_box().clear } - /// 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 fragments it is responsible for flowing. /// /// TODO(pcwalton): Inline blocks. - fn bubble_widths(&mut self, _: &mut LayoutContext) { + fn bubble_inline_sizes(&mut self, _: &mut LayoutContext) { let mut flags = self.base.flags; flags.set_has_left_floated_descendants(false); flags.set_has_right_floated_descendants(false); - // Find the maximum width from children. - let mut intrinsic_widths = IntrinsicWidths::new(); + // Find the maximum inline-size from children. + let mut intrinsic_inline_sizes = IntrinsicISizes::new(); for child_ctx in self.base.child_iter() { assert!(child_ctx.is_block_flow() || child_ctx.is_inline_flow() || child_ctx.is_table_kind()); let child_base = flow::mut_base(child_ctx); - intrinsic_widths.minimum_width = - geometry::max(intrinsic_widths.minimum_width, - child_base.intrinsic_widths.total_minimum_width()); - intrinsic_widths.preferred_width = - geometry::max(intrinsic_widths.preferred_width, - child_base.intrinsic_widths.total_preferred_width()); + intrinsic_inline_sizes.minimum_inline_size = + geometry::max(intrinsic_inline_sizes.minimum_inline_size, + child_base.intrinsic_inline_sizes.total_minimum_inline_size()); + intrinsic_inline_sizes.preferred_inline_size = + geometry::max(intrinsic_inline_sizes.preferred_inline_size, + child_base.intrinsic_inline_sizes.total_preferred_inline_size()); flags.union_floated_descendants_flags(child_base.flags); } - let fragment_intrinsic_widths = self.fragment.intrinsic_widths(None); - intrinsic_widths.minimum_width = geometry::max(intrinsic_widths.minimum_width, - fragment_intrinsic_widths.minimum_width); - intrinsic_widths.preferred_width = geometry::max(intrinsic_widths.preferred_width, - fragment_intrinsic_widths.preferred_width); - intrinsic_widths.surround_width = fragment_intrinsic_widths.surround_width; - self.base.intrinsic_widths = intrinsic_widths; + let fragment_intrinsic_inline_sizes = self.fragment.intrinsic_inline_sizes(None); + 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 = geometry::max(intrinsic_inline_sizes.preferred_inline_size, + fragment_intrinsic_inline_sizes.preferred_inline_size); + intrinsic_inline_sizes.surround_inline_size = fragment_intrinsic_inline_sizes.surround_inline_size; + self.base.intrinsic_inline_sizes = intrinsic_inline_sizes; match self.fragment.style().get_box().float { float::none => {} @@ -1464,13 +1483,13 @@ impl Flow for BlockFlow { self.base.flags = flags } - /// 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, layout_context: &mut LayoutContext) { - debug!("assign_widths({}): assigning width for flow", + fn assign_inline_sizes(&mut self, layout_context: &mut LayoutContext) { + debug!("assign_inline_sizes({}): assigning inline_size for flow", if self.is_float() { "float" } else { @@ -1479,21 +1498,22 @@ impl Flow for BlockFlow { if self.is_root() { debug!("Setting root position"); - self.base.position.origin = Zero::zero(); - self.base.position.size.width = layout_context.screen_size.width; - self.base.floats = Floats::new(); + self.base.position.start = LogicalPoint::zero(self.base.writing_mode); + self.base.position.size.inline = LogicalSize::from_physical( + self.base.writing_mode, layout_context.screen_size).inline; + self.base.floats = Floats::new(self.base.writing_mode); // The root element is never impacted by floats. self.base.flags.set_impacted_by_left_floats(false); self.base.flags.set_impacted_by_right_floats(false); } - // Our width was set to the width of the containing block by the flow's parent. Now compute + // Our inline-size was set to the inline-size of the containing block by the flow's parent. Now compute // the real value. - let containing_block_width = self.base.position.size.width; - self.compute_used_width(layout_context, containing_block_width); + let containing_block_inline_size = self.base.position.size.inline; + self.compute_used_inline_size(layout_context, containing_block_inline_size); if self.is_float() { - self.float.get_mut_ref().containing_width = containing_block_width; + self.float.get_mut_ref().containing_inline_size = containing_block_inline_size; } // Formatting contexts are never impacted by floats. @@ -1503,14 +1523,14 @@ impl Flow for BlockFlow { self.base.flags.set_impacted_by_left_floats(false); self.base.flags.set_impacted_by_right_floats(false); - // We can't actually compute the width of this block now, because floats might - // affect it. Speculate that its width is equal to the width computed above minus - // the width of the previous float. - match self.previous_float_width { + // We can't actually compute the inline-size of this block now, because floats might + // affect it. Speculate that its inline-size is equal to the inline-size computed above minus + // the inline-size of the previous float. + match self.previous_float_inline_size { None => {} - Some(previous_float_width) => { - self.fragment.border_box.size.width = - self.fragment.border_box.size.width - previous_float_width + Some(previous_float_inline_size) => { + self.fragment.border_box.size.inline = + self.fragment.border_box.size.inline - previous_float_inline_size } } } @@ -1520,25 +1540,25 @@ impl Flow for BlockFlow { } } - // Move in from the left border edge - let left_content_edge = self.fragment.border_box.origin.x + self.fragment.border_padding.left; - let padding_and_borders = self.fragment.border_padding.horizontal(); - let content_width = self.fragment.border_box.size.width - padding_and_borders; + // Move in from the inline-start border edge + let inline_start_content_edge = self.fragment.border_box.start.i + self.fragment.border_padding.inline_start; + let padding_and_borders = self.fragment.border_padding.inline_start_end(); + let content_inline_size = self.fragment.border_box.size.inline - padding_and_borders; if self.is_float() { - self.base.position.size.width = content_width; + self.base.position.size.inline = content_inline_size; } - self.propagate_assigned_width_to_children(left_content_edge, content_width, None); + self.propagate_assigned_inline_size_to_children(inline_start_content_edge, content_inline_size, None); } - /// 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. /// - /// This is called on child flows by the parent. Hence, we can assume that `assign_height` has + /// This is called on child flows by the parent. Hence, we can assume that `assign_block-size` has /// already been called on the child (because of the bottom-up traversal). - 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 { if self.is_float() { self.place_float(); @@ -1547,21 +1567,21 @@ impl Flow for BlockFlow { let impacted = self.base.flags.impacted_by_floats(); if impacted { - self.assign_height(layout_context); + self.assign_block_size(layout_context); } impacted } - fn assign_height(&mut self, ctx: &mut LayoutContext) { - // Assign height for fragment if it is an image fragment. - self.fragment.assign_replaced_height_if_necessary(); + fn assign_block_size(&mut self, ctx: &mut LayoutContext) { + // Assign block-size for fragment if it is an image fragment. + self.fragment.assign_replaced_block_size_if_necessary(); if self.is_float() { - debug!("assign_height_float: assigning height for float"); - self.assign_height_float(ctx); + debug!("assign_block_size_float: assigning block_size for float"); + self.assign_block_size_float(ctx); } else { - debug!("assign_height: assigning height for block"); - self.assign_height_block_base(ctx, MarginsMayCollapse); + debug!("assign_block_size: assigning block_size for block"); + self.assign_block_size_block_base(ctx, MarginsMayCollapse); } } @@ -1571,12 +1591,12 @@ impl Flow for BlockFlow { .absolute_position_info .absolute_containing_block_position = if self.is_fixed() { // The viewport is initially at (0, 0). - self.base.position.origin + self.base.position.start } else { // Absolute position of the containing block + position of absolute flow w/r/t the // containing block. - self.base.absolute_position_info.absolute_containing_block_position + - self.base.position.origin + self.base.absolute_position_info.absolute_containing_block_position + .add_point(&self.base.position.start) }; // Set the absolute position, which will be passed down later as part @@ -1595,15 +1615,15 @@ impl Flow for BlockFlow { None); if self.is_positioned() { self.base.absolute_position_info.absolute_containing_block_position = - self.base.abs_position + - self.generated_containing_block_rect().origin + - relative_offset + self.base.abs_position + .add_point(&self.generated_containing_block_rect().start) + + relative_offset } let float_offset = if self.is_float() { self.float.get_ref().rel_pos } else { - Zero::zero() + LogicalPoint::zero(self.base.writing_mode) }; // Compute absolute position info for children. @@ -1617,8 +1637,11 @@ impl Flow for BlockFlow { for kid in self.base.child_iter() { if !kid.is_absolutely_positioned() { let kid_base = flow::mut_base(kid); - kid_base.abs_position = this_position + kid_base.position.origin + - relative_offset + float_offset; + kid_base.abs_position = + this_position + .add_point(&kid_base.position.start) + .add_point(&float_offset) + + relative_offset; kid_base.absolute_position_info = absolute_position_info } } @@ -1662,11 +1685,8 @@ impl Flow for BlockFlow { /// 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 { - let border = model::border_from_style(self.fragment.style()); - Rect(self.fragment.border_box.origin + Point2D(border.left, border.top), - Size2D(self.fragment.border_box.size.width - border.horizontal(), - self.fragment.border_box.size.height - border.vertical())) + fn generated_containing_block_rect(&self) -> LogicalRect { + self.fragment.border_box - self.fragment.style().logical_border_width() } fn layer_id(&self, fragment_index: uint) -> LayerId { @@ -1693,289 +1713,275 @@ impl fmt::Show for BlockFlow { } } -/// The inputs for the widths-and-margins constraint equation. -pub struct WidthConstraintInput { - pub computed_width: MaybeAuto, - pub left_margin: MaybeAuto, - pub right_margin: MaybeAuto, - pub left: MaybeAuto, - pub right: MaybeAuto, - pub available_width: Au, - pub static_x_offset: Au, - pub direction: direction::T, +/// The inputs for the inline-sizes-and-margins constraint equation. +pub struct ISizeConstraintInput { + pub computed_inline_size: MaybeAuto, + pub inline_start_margin: MaybeAuto, + pub inline_end_margin: MaybeAuto, + pub inline_start: MaybeAuto, + pub inline_end: MaybeAuto, + pub available_inline_size: Au, + pub static_i_offset: Au, } -impl WidthConstraintInput { - pub fn new(computed_width: MaybeAuto, - left_margin: MaybeAuto, - right_margin: MaybeAuto, - left: MaybeAuto, - right: MaybeAuto, - available_width: Au, - static_x_offset: Au, - direction: direction::T) - -> WidthConstraintInput { - WidthConstraintInput { - computed_width: computed_width, - left_margin: left_margin, - right_margin: right_margin, - left: left, - right: right, - available_width: available_width, - static_x_offset: static_x_offset, - direction: direction, +impl ISizeConstraintInput { + pub fn new(computed_inline_size: MaybeAuto, + inline_start_margin: MaybeAuto, + inline_end_margin: MaybeAuto, + inline_start: MaybeAuto, + inline_end: MaybeAuto, + available_inline_size: Au, + static_i_offset: Au) + -> ISizeConstraintInput { + ISizeConstraintInput { + computed_inline_size: computed_inline_size, + inline_start_margin: inline_start_margin, + inline_end_margin: inline_end_margin, + inline_start: inline_start, + inline_end: inline_end, + available_inline_size: available_inline_size, + static_i_offset: static_i_offset, } } } -/// The solutions for the widths-and-margins constraint equation. -pub struct WidthConstraintSolution { - pub left: Au, - pub right: Au, - pub width: Au, - pub margin_left: Au, - pub margin_right: Au +/// The solutions for the inline-size-and-margins constraint equation. +pub struct ISizeConstraintSolution { + pub inline_start: Au, + pub inline_end: Au, + pub inline_size: Au, + pub margin_inline_start: Au, + pub margin_inline_end: Au } -impl WidthConstraintSolution { - pub fn new(width: Au, margin_left: Au, margin_right: Au) -> WidthConstraintSolution { - WidthConstraintSolution { - left: Au(0), - right: Au(0), - width: width, - margin_left: margin_left, - margin_right: margin_right, +impl ISizeConstraintSolution { + pub fn new(inline_size: Au, margin_inline_start: Au, margin_inline_end: Au) -> ISizeConstraintSolution { + ISizeConstraintSolution { + inline_start: Au(0), + inline_end: Au(0), + inline_size: inline_size, + margin_inline_start: margin_inline_start, + margin_inline_end: margin_inline_end, } } - fn for_absolute_flow(left: Au, - right: Au, - width: Au, - margin_left: Au, - margin_right: Au) - -> WidthConstraintSolution { - WidthConstraintSolution { - left: left, - right: right, - width: width, - margin_left: margin_left, - margin_right: margin_right, + fn for_absolute_flow(inline_start: Au, + inline_end: Au, + inline_size: Au, + margin_inline_start: Au, + margin_inline_end: Au) + -> ISizeConstraintSolution { + ISizeConstraintSolution { + inline_start: inline_start, + inline_end: inline_end, + inline_size: inline_size, + margin_inline_start: margin_inline_start, + margin_inline_end: margin_inline_end, } } } -// Trait to encapsulate the Width and Margin calculation. +// Trait to encapsulate the ISize and Margin calculation. // // CSS Section 10.3 -pub trait WidthAndMarginsComputer { - /// Compute the inputs for the Width constraint equation. +pub trait ISizeAndMarginsComputer { + /// Compute the inputs for the ISize constraint equation. /// /// This is called only once to compute the initial inputs. For - /// calculation involving min-width and max-width, we don't need to + /// calculation involving min-inline-size and max-inline-size, we don't need to /// recompute these. - fn compute_width_constraint_inputs(&self, + fn compute_inline_size_constraint_inputs(&self, block: &mut BlockFlow, - parent_flow_width: Au, + parent_flow_inline_size: Au, ctx: &mut LayoutContext) - -> WidthConstraintInput { - let containing_block_width = self.containing_block_width(block, parent_flow_width, ctx); - let computed_width = self.initial_computed_width(block, parent_flow_width, ctx); + -> ISizeConstraintInput { + let containing_block_inline_size = self.containing_block_inline_size(block, parent_flow_inline_size, ctx); + let computed_inline_size = self.initial_computed_inline_size(block, parent_flow_inline_size, ctx); - block.fragment.compute_border_padding_margins(containing_block_width, None); + block.fragment.compute_border_padding_margins(containing_block_inline_size, None); let style = block.fragment.style(); // The text alignment of a block flow is the text alignment of its box's style. block.base.flags.set_text_align(style.get_inheritedtext().text_align); - let (margin_left, margin_right) = - (MaybeAuto::from_style(style.get_margin().margin_left, containing_block_width), - MaybeAuto::from_style(style.get_margin().margin_right, containing_block_width)); + let margin = style.logical_margin(); + let position = style.logical_position(); - let (left, right) = - (MaybeAuto::from_style(style.get_positionoffsets().left, containing_block_width), - MaybeAuto::from_style(style.get_positionoffsets().right, containing_block_width)); - let available_width = containing_block_width - block.fragment.border_padding.horizontal(); - return WidthConstraintInput::new(computed_width, - margin_left, - margin_right, - left, - right, - available_width, - block.static_x_offset(), - style.get_inheritedbox().direction); + let available_inline_size = containing_block_inline_size - block.fragment.border_padding.inline_start_end(); + return ISizeConstraintInput::new( + computed_inline_size, + MaybeAuto::from_style(margin.inline_start, containing_block_inline_size), + MaybeAuto::from_style(margin.inline_end, containing_block_inline_size), + MaybeAuto::from_style(position.inline_start, containing_block_inline_size), + MaybeAuto::from_style(position.inline_end, containing_block_inline_size), + available_inline_size, + block.static_i_offset()); } - /// Set the used values for width and margins got from the relevant constraint equation. + /// Set the used values for inline-size and margins got from the relevant constraint equation. /// /// This is called only once. /// /// Set: - /// + used values for content width, left margin, and right margin for this flow's box. + /// + used values for content inline-size, inline-start margin, and inline-end margin for this flow's box. /// + x-coordinate of this flow's box. /// + x-coordinate of the flow wrt its Containing Block (if this is an absolute flow). - fn set_width_constraint_solutions(&self, + fn set_inline_size_constraint_solutions(&self, block: &mut BlockFlow, - solution: WidthConstraintSolution) { - let width; + solution: ISizeConstraintSolution) { + let inline_size; { let fragment = block.fragment(); - fragment.margin.left = solution.margin_left; - fragment.margin.right = solution.margin_right; + fragment.margin.inline_start = solution.margin_inline_start; + fragment.margin.inline_end = solution.margin_inline_end; // The associated fragment has the border box of this flow. // Left border edge. - fragment.border_box.origin.x = fragment.margin.left; - // Border box width. - width = solution.width + fragment.border_padding.horizontal(); - fragment.border_box.size.width = width; + fragment.border_box.start.i = fragment.margin.inline_start; + // Border box inline-size. + inline_size = solution.inline_size + fragment.border_padding.inline_start_end(); + fragment.border_box.size.inline = inline_size; } // We also resize the block itself, to ensure that overflow is not calculated - // as the width of our parent. We might be smaller and we might be larger if we + // as the inline-size of our parent. We might be smaller and we might be larger if we // overflow. let flow = flow::mut_base(block); - flow.position.size.width = width; + flow.position.size.inline = inline_size; } /// Set the x coordinate of the given flow if it is absolutely positioned. - fn set_flow_x_coord_if_necessary(&self, _: &mut BlockFlow, _: WidthConstraintSolution) {} + fn set_flow_x_coord_if_necessary(&self, _: &mut BlockFlow, _: ISizeConstraintSolution) {} - /// Solve the width and margins constraints for this block flow. - fn solve_width_constraints(&self, + /// Solve the inline-size and margins constraints for this block flow. + fn solve_inline_size_constraints(&self, block: &mut BlockFlow, - input: &WidthConstraintInput) - -> WidthConstraintSolution; + input: &ISizeConstraintInput) + -> ISizeConstraintSolution; - fn initial_computed_width(&self, + fn initial_computed_inline_size(&self, block: &mut BlockFlow, - parent_flow_width: Au, + parent_flow_inline_size: Au, ctx: &mut LayoutContext) -> MaybeAuto { - MaybeAuto::from_style(block.fragment().style().get_box().width, - self.containing_block_width(block, parent_flow_width, ctx)) + MaybeAuto::from_style(block.fragment().style().content_inline_size(), + self.containing_block_inline_size(block, parent_flow_inline_size, ctx)) } - fn containing_block_width(&self, + fn containing_block_inline_size(&self, _: &mut BlockFlow, - parent_flow_width: Au, + parent_flow_inline_size: Au, _: &mut LayoutContext) -> Au { - parent_flow_width + parent_flow_inline_size } - /// Compute the used value of width, taking care of min-width and max-width. + /// 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 mut input = self.compute_width_constraint_inputs(block, parent_flow_width, ctx); + parent_flow_inline_size: Au) { + let mut input = self.compute_inline_size_constraint_inputs(block, parent_flow_inline_size, ctx); - let containing_block_width = self.containing_block_width(block, parent_flow_width, ctx); + let containing_block_inline_size = self.containing_block_inline_size(block, parent_flow_inline_size, ctx); - let mut solution = self.solve_width_constraints(block, &input); + let mut solution = self.solve_inline_size_constraints(block, &input); - // If the tentative used width is greater than 'max-width', width should be recalculated, - // but this time using the computed value of 'max-width' as the computed value for 'width'. - match specified_or_none(block.fragment().style().get_box().max_width, containing_block_width) { - Some(max_width) if max_width < solution.width => { - input.computed_width = Specified(max_width); - solution = self.solve_width_constraints(block, &input); + // If the tentative used inline-size is greater than 'max-inline-size', inline-size should be recalculated, + // but this time using the computed value of 'max-inline-size' as the computed value for 'inline-size'. + match specified_or_none(block.fragment().style().max_inline_size(), containing_block_inline_size) { + Some(max_inline_size) if max_inline_size < solution.inline_size => { + input.computed_inline_size = Specified(max_inline_size); + solution = self.solve_inline_size_constraints(block, &input); } _ => {} } - // If the resulting width is smaller than 'min-width', width should be recalculated, - // but this time using the value of 'min-width' as the computed value for 'width'. - let computed_min_width = specified(block.fragment().style().get_box().min_width, - containing_block_width); - if computed_min_width > solution.width { - input.computed_width = Specified(computed_min_width); - solution = self.solve_width_constraints(block, &input); + // If the resulting inline-size is smaller than 'min-inline-size', inline-size should be recalculated, + // but this time using the value of 'min-inline-size' as the computed value for 'inline-size'. + let computed_min_inline_size = specified(block.fragment().style().min_inline_size(), + containing_block_inline_size); + if computed_min_inline_size > solution.inline_size { + input.computed_inline_size = Specified(computed_min_inline_size); + solution = self.solve_inline_size_constraints(block, &input); } - self.set_width_constraint_solutions(block, solution); + self.set_inline_size_constraint_solutions(block, solution); self.set_flow_x_coord_if_necessary(block, solution); } - /// Computes left and right margins and width. + /// Computes inline-start and inline-end margins and inline-size. /// /// This is used by both replaced and non-replaced Blocks. /// /// CSS 2.1 Section 10.3.3. - /// Constraint Equation: margin-left + margin-right + width = available_width - /// where available_width = CB width - (horizontal border + padding) - fn solve_block_width_constraints(&self, + /// Constraint Equation: margin-inline-start + margin-inline-end + inline-size = available_inline-size + /// where available_inline-size = CB inline-size - (horizontal border + padding) + fn solve_block_inline_size_constraints(&self, _: &mut BlockFlow, - input: &WidthConstraintInput) - -> WidthConstraintSolution { - let (computed_width, left_margin, right_margin, available_width) = (input.computed_width, - input.left_margin, - input.right_margin, - input.available_width); + input: &ISizeConstraintInput) + -> ISizeConstraintSolution { + let (computed_inline_size, inline_start_margin, inline_end_margin, available_inline_size) = (input.computed_inline_size, + input.inline_start_margin, + input.inline_end_margin, + input.available_inline_size); - // If width is not 'auto', and width + margins > available_width, all + // If inline-size is not 'auto', and inline-size + margins > available_inline-size, all // 'auto' margins are treated as 0. - let (left_margin, right_margin) = match computed_width { - Auto => (left_margin, right_margin), - Specified(width) => { - let left = left_margin.specified_or_zero(); - let right = right_margin.specified_or_zero(); + let (inline_start_margin, inline_end_margin) = match computed_inline_size { + Auto => (inline_start_margin, inline_end_margin), + Specified(inline_size) => { + let inline_start = inline_start_margin.specified_or_zero(); + let inline_end = inline_end_margin.specified_or_zero(); - if (left + right + width) > available_width { - (Specified(left), Specified(right)) + if (inline_start + inline_end + inline_size) > available_inline_size { + (Specified(inline_start), Specified(inline_end)) } else { - (left_margin, right_margin) + (inline_start_margin, inline_end_margin) } } }; - // Invariant: left_margin + width + right_margin == available_width - let (left_margin, width, right_margin) = match (left_margin, computed_width, right_margin) { + // Invariant: inline-start_margin + inline-size + inline-end_margin == available_inline-size + let (inline_start_margin, inline_size, inline_end_margin) = match (inline_start_margin, computed_inline_size, inline_end_margin) { // If all have a computed value other than 'auto', the system is - // over-constrained and we need to discard a margin. - // If direction is ltr, ignore the specified right margin and - // solve for it. - // If it is rtl, ignore the specified left margin. - (Specified(margin_l), Specified(width), Specified(margin_r)) => { - match input.direction { - direction::ltr => (margin_l, width, available_width - (margin_l + width)), - direction::rtl => (available_width - (margin_r + width), width, margin_r), - } - }, + // over-constrained so we discard the end margin. + (Specified(margin_start), Specified(inline_size), Specified(_margin_end)) => + (margin_start, inline_size, available_inline_size - (margin_start + inline_size)), // If exactly one value is 'auto', solve for it - (Auto, Specified(width), Specified(margin_r)) => - (available_width - (width + margin_r), width, margin_r), - (Specified(margin_l), Auto, Specified(margin_r)) => - (margin_l, available_width - (margin_l + margin_r), margin_r), - (Specified(margin_l), Specified(width), Auto) => - (margin_l, width, available_width - (margin_l + width)), + (Auto, Specified(inline_size), Specified(margin_end)) => + (available_inline_size - (inline_size + margin_end), inline_size, margin_end), + (Specified(margin_start), Auto, Specified(margin_end)) => + (margin_start, available_inline_size - (margin_start + margin_end), margin_end), + (Specified(margin_start), Specified(inline_size), Auto) => + (margin_start, inline_size, available_inline_size - (margin_start + inline_size)), - // If width is set to 'auto', any other 'auto' value becomes '0', - // and width is solved for - (Auto, Auto, Specified(margin_r)) => - (Au::new(0), available_width - margin_r, margin_r), - (Specified(margin_l), Auto, Auto) => - (margin_l, available_width - margin_l, Au::new(0)), + // If inline-size is set to 'auto', any other 'auto' value becomes '0', + // and inline-size is solved for + (Auto, Auto, Specified(margin_end)) => + (Au::new(0), available_inline_size - margin_end, margin_end), + (Specified(margin_start), Auto, Auto) => + (margin_start, available_inline_size - margin_start, Au::new(0)), (Auto, Auto, Auto) => - (Au::new(0), available_width, Au::new(0)), + (Au::new(0), available_inline_size, Au::new(0)), - // If left and right margins are auto, they become equal - (Auto, Specified(width), Auto) => { - let margin = (available_width - width).scale_by(0.5); - (margin, width, margin) + // If inline-start and inline-end margins are auto, they become equal + (Auto, Specified(inline_size), Auto) => { + let margin = (available_inline_size - inline_size).scale_by(0.5); + (margin, inline_size, margin) } }; - WidthConstraintSolution::new(width, left_margin, right_margin) + ISizeConstraintSolution::new(inline_size, inline_start_margin, inline_end_margin) } } /// The different types of Blocks. /// -/// They mainly differ in the way width and heights and margins are calculated +/// They mainly differ in the way inline-size and block-sizes and margins are calculated /// for them. struct AbsoluteNonReplaced; struct AbsoluteReplaced; @@ -1984,28 +1990,28 @@ struct BlockReplaced; struct FloatNonReplaced; struct FloatReplaced; -impl WidthAndMarginsComputer for AbsoluteNonReplaced { +impl ISizeAndMarginsComputer for AbsoluteNonReplaced { /// Solve the horizontal constraint equation for absolute non-replaced elements. /// /// CSS Section 10.3.7 /// Constraint equation: - /// left + right + width + margin-left + margin-right - /// = absolute containing block width - (horizontal padding and border) - /// [aka available_width] + /// inline-start + inline-end + inline-size + margin-inline-start + margin-inline-end + /// = absolute containing block inline-size - (horizontal padding and border) + /// [aka available_inline-size] /// /// Return the solution for the equation. - fn solve_width_constraints(&self, + fn solve_inline_size_constraints(&self, block: &mut BlockFlow, - input: &WidthConstraintInput) - -> WidthConstraintSolution { - let &WidthConstraintInput { - computed_width, - left_margin, - right_margin, - left, - right, - available_width, - static_x_offset, + input: &ISizeConstraintInput) + -> ISizeConstraintSolution { + let &ISizeConstraintInput { + computed_inline_size, + inline_start_margin, + inline_end_margin, + inline_start, + inline_end, + available_inline_size, + static_i_offset, .. } = input; @@ -2013,148 +2019,148 @@ impl WidthAndMarginsComputer for AbsoluteNonReplaced { // when right-to-left is implemented. // Assume direction is 'ltr' for now - // Distance from the left edge of the Absolute Containing Block to the - // left margin edge of a hypothetical box that would have been the + // Distance from the inline-start edge of the Absolute Containing Block to the + // inline-start margin edge of a hypothetical box that would have been the // first box of the element. - let static_position_left = static_x_offset; + let static_position_inline_start = static_i_offset; - let (left, right, width, margin_left, margin_right) = match (left, right, computed_width) { + let (inline_start, inline_end, inline_size, margin_inline_start, margin_inline_end) = match (inline_start, inline_end, computed_inline_size) { (Auto, Auto, Auto) => { - let margin_l = left_margin.specified_or_zero(); - let margin_r = right_margin.specified_or_zero(); - let left = static_position_left; - // Now it is the same situation as left Specified and right - // and width Auto. + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + let inline_start = static_position_inline_start; + // Now it is the same situation as inline-start Specified and inline-end + // and inline-size Auto. - // Set right to zero to calculate width - let width = block.get_shrink_to_fit_width( - available_width - (left + margin_l + margin_r)); - let sum = left + width + margin_l + margin_r; - (left, available_width - sum, width, margin_l, margin_r) + // Set inline-end to zero to calculate inline-size + let inline_size = block.get_shrink_to_fit_inline_size( + available_inline_size - (inline_start + margin_start + margin_end)); + let sum = inline_start + inline_size + margin_start + margin_end; + (inline_start, available_inline_size - sum, inline_size, margin_start, margin_end) } - (Specified(left), Specified(right), Specified(width)) => { - match (left_margin, right_margin) { + (Specified(inline_start), Specified(inline_end), Specified(inline_size)) => { + match (inline_start_margin, inline_end_margin) { (Auto, Auto) => { - let total_margin_val = available_width - left - right - width; + let total_margin_val = available_inline_size - inline_start - inline_end - inline_size; if total_margin_val < Au(0) { - // margin-left becomes 0 because direction is 'ltr'. + // margin-inline-start becomes 0 because direction is 'ltr'. // TODO: Handle 'rtl' when it is implemented. - (left, right, width, Au(0), total_margin_val) + (inline_start, inline_end, inline_size, Au(0), total_margin_val) } else { // Equal margins - (left, right, width, + (inline_start, inline_end, inline_size, total_margin_val.scale_by(0.5), total_margin_val.scale_by(0.5)) } } - (Specified(margin_l), Auto) => { - let sum = left + right + width + margin_l; - (left, right, width, margin_l, available_width - sum) + (Specified(margin_start), Auto) => { + let sum = inline_start + inline_end + inline_size + margin_start; + (inline_start, inline_end, inline_size, margin_start, available_inline_size - sum) } - (Auto, Specified(margin_r)) => { - let sum = left + right + width + margin_r; - (left, right, width, available_width - sum, margin_r) + (Auto, Specified(margin_end)) => { + let sum = inline_start + inline_end + inline_size + margin_end; + (inline_start, inline_end, inline_size, available_inline_size - sum, margin_end) } - (Specified(margin_l), Specified(margin_r)) => { + (Specified(margin_start), Specified(margin_end)) => { // Values are over-constrained. - // Ignore value for 'right' cos direction is 'ltr'. + // Ignore value for 'inline-end' cos direction is 'ltr'. // TODO: Handle 'rtl' when it is implemented. - let sum = left + width + margin_l + margin_r; - (left, available_width - sum, width, margin_l, margin_r) + let sum = inline_start + inline_size + margin_start + margin_end; + (inline_start, available_inline_size - sum, inline_size, margin_start, margin_end) } } } // For the rest of the cases, auto values for margin are set to 0 // If only one is Auto, solve for it - (Auto, Specified(right), Specified(width)) => { - let margin_l = left_margin.specified_or_zero(); - let margin_r = right_margin.specified_or_zero(); - let sum = right + width + margin_l + margin_r; - (available_width - sum, right, width, margin_l, margin_r) + (Auto, Specified(inline_end), Specified(inline_size)) => { + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + let sum = inline_end + inline_size + margin_start + margin_end; + (available_inline_size - sum, inline_end, inline_size, margin_start, margin_end) } - (Specified(left), Auto, Specified(width)) => { - let margin_l = left_margin.specified_or_zero(); - let margin_r = right_margin.specified_or_zero(); - let sum = left + width + margin_l + margin_r; - (left, available_width - sum, width, margin_l, margin_r) + (Specified(inline_start), Auto, Specified(inline_size)) => { + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + let sum = inline_start + inline_size + margin_start + margin_end; + (inline_start, available_inline_size - sum, inline_size, margin_start, margin_end) } - (Specified(left), Specified(right), Auto) => { - let margin_l = left_margin.specified_or_zero(); - let margin_r = right_margin.specified_or_zero(); - let sum = left + right + margin_l + margin_r; - (left, right, available_width - sum, margin_l, margin_r) + (Specified(inline_start), Specified(inline_end), Auto) => { + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + let sum = inline_start + inline_end + margin_start + margin_end; + (inline_start, inline_end, available_inline_size - sum, margin_start, margin_end) } - // If width is auto, then width is shrink-to-fit. Solve for the + // If inline-size is auto, then inline-size is shrink-to-fit. Solve for the // non-auto value. - (Specified(left), Auto, Auto) => { - let margin_l = left_margin.specified_or_zero(); - let margin_r = right_margin.specified_or_zero(); - // Set right to zero to calculate width - let width = block.get_shrink_to_fit_width( - available_width - (left + margin_l + margin_r)); - let sum = left + width + margin_l + margin_r; - (left, available_width - sum, width, margin_l, margin_r) + (Specified(inline_start), Auto, Auto) => { + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + // Set inline-end to zero to calculate inline-size + let inline_size = block.get_shrink_to_fit_inline_size( + available_inline_size - (inline_start + margin_start + margin_end)); + let sum = inline_start + inline_size + margin_start + margin_end; + (inline_start, available_inline_size - sum, inline_size, margin_start, margin_end) } - (Auto, Specified(right), Auto) => { - let margin_l = left_margin.specified_or_zero(); - let margin_r = right_margin.specified_or_zero(); - // Set left to zero to calculate width - let width = block.get_shrink_to_fit_width( - available_width - (right + margin_l + margin_r)); - let sum = right + width + margin_l + margin_r; - (available_width - sum, right, width, margin_l, margin_r) + (Auto, Specified(inline_end), Auto) => { + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + // Set inline-start to zero to calculate inline-size + let inline_size = block.get_shrink_to_fit_inline_size( + available_inline_size - (inline_end + margin_start + margin_end)); + let sum = inline_end + inline_size + margin_start + margin_end; + (available_inline_size - sum, inline_end, inline_size, margin_start, margin_end) } - (Auto, Auto, Specified(width)) => { - let margin_l = left_margin.specified_or_zero(); - let margin_r = right_margin.specified_or_zero(); - // Setting 'left' to static position because direction is 'ltr'. + (Auto, Auto, Specified(inline_size)) => { + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + // Setting 'inline-start' to static position because direction is 'ltr'. // TODO: Handle 'rtl' when it is implemented. - let left = static_position_left; - let sum = left + width + margin_l + margin_r; - (left, available_width - sum, width, margin_l, margin_r) + let inline_start = static_position_inline_start; + let sum = inline_start + inline_size + margin_start + margin_end; + (inline_start, available_inline_size - sum, inline_size, margin_start, margin_end) } }; - WidthConstraintSolution::for_absolute_flow(left, right, width, margin_left, margin_right) + ISizeConstraintSolution::for_absolute_flow(inline_start, inline_end, inline_size, margin_inline_start, margin_inline_end) } - fn containing_block_width(&self, block: &mut BlockFlow, _: Au, ctx: &mut LayoutContext) -> Au { - block.containing_block_size(ctx.screen_size).width + fn containing_block_inline_size(&self, block: &mut BlockFlow, _: Au, ctx: &mut LayoutContext) -> Au { + block.containing_block_size(ctx.screen_size).inline } fn set_flow_x_coord_if_necessary(&self, block: &mut BlockFlow, - solution: WidthConstraintSolution) { + solution: ISizeConstraintSolution) { // Set the x-coordinate of the absolute flow wrt to its containing block. - block.base.position.origin.x = solution.left; + block.base.position.start.i = solution.inline_start; } } -impl WidthAndMarginsComputer for AbsoluteReplaced { +impl ISizeAndMarginsComputer for AbsoluteReplaced { /// Solve the horizontal constraint equation for absolute replaced elements. /// - /// `static_x_offset`: total offset of current flow's hypothetical + /// `static_i_offset`: total offset of current flow's hypothetical /// position (static position) from its actual Containing Block. /// /// CSS Section 10.3.8 /// Constraint equation: - /// left + right + width + margin-left + margin-right - /// = absolute containing block width - (horizontal padding and border) - /// [aka available_width] + /// inline-start + inline-end + inline-size + margin-inline-start + margin-inline-end + /// = absolute containing block inline-size - (horizontal padding and border) + /// [aka available_inline-size] /// /// Return the solution for the equation. - fn solve_width_constraints(&self, _: &mut BlockFlow, input: &WidthConstraintInput) - -> WidthConstraintSolution { - let &WidthConstraintInput { - computed_width, - left_margin, - right_margin, - left, - right, - available_width, - static_x_offset, + fn solve_inline_size_constraints(&self, _: &mut BlockFlow, input: &ISizeConstraintInput) + -> ISizeConstraintSolution { + let &ISizeConstraintInput { + computed_inline_size, + inline_start_margin, + inline_end_margin, + inline_start, + inline_end, + available_inline_size, + static_i_offset, .. } = input; // TODO: Check for direction of static-position Containing Block (aka @@ -2163,224 +2169,224 @@ impl WidthAndMarginsComputer for AbsoluteReplaced { // Assume direction is 'ltr' for now // TODO: Handle all the cases for 'rtl' direction. - let width = match computed_width { + let inline_size = match computed_inline_size { Specified(w) => w, _ => fail!("{} {}", - "The used value for width for absolute replaced flow", + "The used value for inline_size for absolute replaced flow", "should have already been calculated by now.") }; - // Distance from the left edge of the Absolute Containing Block to the - // left margin edge of a hypothetical box that would have been the + // Distance from the inline-start edge of the Absolute Containing Block to the + // inline-start margin edge of a hypothetical box that would have been the // first box of the element. - let static_position_left = static_x_offset; + let static_position_inline_start = static_i_offset; - let (left, right, width, margin_left, margin_right) = match (left, right) { + let (inline_start, inline_end, inline_size, margin_inline_start, margin_inline_end) = match (inline_start, inline_end) { (Auto, Auto) => { - let left = static_position_left; - let margin_l = left_margin.specified_or_zero(); - let margin_r = right_margin.specified_or_zero(); - let sum = left + width + margin_l + margin_r; - (left, available_width - sum, width, margin_l, margin_r) + let inline_start = static_position_inline_start; + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + let sum = inline_start + inline_size + margin_start + margin_end; + (inline_start, available_inline_size - sum, inline_size, margin_start, margin_end) } // If only one is Auto, solve for it - (Auto, Specified(right)) => { - let margin_l = left_margin.specified_or_zero(); - let margin_r = right_margin.specified_or_zero(); - let sum = right + width + margin_l + margin_r; - (available_width - sum, right, width, margin_l, margin_r) + (Auto, Specified(inline_end)) => { + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + let sum = inline_end + inline_size + margin_start + margin_end; + (available_inline_size - sum, inline_end, inline_size, margin_start, margin_end) } - (Specified(left), Auto) => { - let margin_l = left_margin.specified_or_zero(); - let margin_r = right_margin.specified_or_zero(); - let sum = left + width + margin_l + margin_r; - (left, available_width - sum, width, margin_l, margin_r) + (Specified(inline_start), Auto) => { + let margin_start = inline_start_margin.specified_or_zero(); + let margin_end = inline_end_margin.specified_or_zero(); + let sum = inline_start + inline_size + margin_start + margin_end; + (inline_start, available_inline_size - sum, inline_size, margin_start, margin_end) } - (Specified(left), Specified(right)) => { - match (left_margin, right_margin) { + (Specified(inline_start), Specified(inline_end)) => { + match (inline_start_margin, inline_end_margin) { (Auto, Auto) => { - let total_margin_val = available_width - left - right - width; + let total_margin_val = available_inline_size - inline_start - inline_end - inline_size; if total_margin_val < Au(0) { - // margin-left becomes 0 because direction is 'ltr'. - (left, right, width, Au(0), total_margin_val) + // margin-inline-start becomes 0 because direction is 'ltr'. + (inline_start, inline_end, inline_size, Au(0), total_margin_val) } else { // Equal margins - (left, right, width, + (inline_start, inline_end, inline_size, total_margin_val.scale_by(0.5), total_margin_val.scale_by(0.5)) } } - (Specified(margin_l), Auto) => { - let sum = left + right + width + margin_l; - (left, right, width, margin_l, available_width - sum) + (Specified(margin_start), Auto) => { + let sum = inline_start + inline_end + inline_size + margin_start; + (inline_start, inline_end, inline_size, margin_start, available_inline_size - sum) } - (Auto, Specified(margin_r)) => { - let sum = left + right + width + margin_r; - (left, right, width, available_width - sum, margin_r) + (Auto, Specified(margin_end)) => { + let sum = inline_start + inline_end + inline_size + margin_end; + (inline_start, inline_end, inline_size, available_inline_size - sum, margin_end) } - (Specified(margin_l), Specified(margin_r)) => { + (Specified(margin_start), Specified(margin_end)) => { // Values are over-constrained. - // Ignore value for 'right' cos direction is 'ltr'. - let sum = left + width + margin_l + margin_r; - (left, available_width - sum, width, margin_l, margin_r) + // Ignore value for 'inline-end' cos direction is 'ltr'. + let sum = inline_start + inline_size + margin_start + margin_end; + (inline_start, available_inline_size - sum, inline_size, margin_start, margin_end) } } } }; - WidthConstraintSolution::for_absolute_flow(left, right, width, margin_left, margin_right) + ISizeConstraintSolution::for_absolute_flow(inline_start, inline_end, inline_size, margin_inline_start, margin_inline_end) } - /// Calculate used value of width just like we do for inline replaced elements. - fn initial_computed_width(&self, + /// Calculate used value of inline-size just like we do for inline replaced elements. + fn initial_computed_inline_size(&self, block: &mut BlockFlow, _: Au, ctx: &mut LayoutContext) -> MaybeAuto { - let containing_block_width = block.containing_block_size(ctx.screen_size).width; + let containing_block_inline_size = block.containing_block_size(ctx.screen_size).inline; let fragment = block.fragment(); - fragment.assign_replaced_width_if_necessary(containing_block_width, None); + fragment.assign_replaced_inline_size_if_necessary(containing_block_inline_size, None); // For replaced absolute flow, the rest of the constraint solving will - // take width to be specified as the value computed here. - Specified(fragment.content_width()) + // take inline-size to be specified as the value computed here. + Specified(fragment.content_inline_size()) } - fn containing_block_width(&self, block: &mut BlockFlow, _: Au, ctx: &mut LayoutContext) -> Au { - block.containing_block_size(ctx.screen_size).width + fn containing_block_inline_size(&self, block: &mut BlockFlow, _: Au, ctx: &mut LayoutContext) -> Au { + block.containing_block_size(ctx.screen_size).inline } - fn set_flow_x_coord_if_necessary(&self, block: &mut BlockFlow, solution: WidthConstraintSolution) { + fn set_flow_x_coord_if_necessary(&self, block: &mut BlockFlow, solution: ISizeConstraintSolution) { // Set the x-coordinate of the absolute flow wrt to its containing block. - block.base.position.origin.x = solution.left; + block.base.position.start.i = solution.inline_start; } } -impl WidthAndMarginsComputer for BlockNonReplaced { - /// Compute left and right margins and width. - fn solve_width_constraints(&self, +impl ISizeAndMarginsComputer for BlockNonReplaced { + /// Compute inline-start and inline-end margins and inline-size. + fn solve_inline_size_constraints(&self, block: &mut BlockFlow, - input: &WidthConstraintInput) - -> WidthConstraintSolution { - self.solve_block_width_constraints(block, input) + input: &ISizeConstraintInput) + -> ISizeConstraintSolution { + self.solve_block_inline_size_constraints(block, input) } } -impl WidthAndMarginsComputer for BlockReplaced { - /// Compute left and right margins and width. +impl ISizeAndMarginsComputer for BlockReplaced { + /// Compute inline-start and inline-end margins and inline-size. /// - /// Width has already been calculated. We now calculate the margins just + /// ISize has already been calculated. We now calculate the margins just /// like for non-replaced blocks. - fn solve_width_constraints(&self, + fn solve_inline_size_constraints(&self, block: &mut BlockFlow, - input: &WidthConstraintInput) - -> WidthConstraintSolution { - match input.computed_width { + input: &ISizeConstraintInput) + -> ISizeConstraintSolution { + match input.computed_inline_size { Specified(_) => {}, - Auto => fail!("BlockReplaced: width should have been computed by now") + Auto => fail!("BlockReplaced: inline_size should have been computed by now") }; - self.solve_block_width_constraints(block, input) + self.solve_block_inline_size_constraints(block, input) } - /// Calculate used value of width just like we do for inline replaced elements. - fn initial_computed_width(&self, + /// Calculate used value of inline-size just like we do for inline replaced elements. + fn initial_computed_inline_size(&self, block: &mut BlockFlow, - parent_flow_width: Au, + parent_flow_inline_size: Au, _: &mut LayoutContext) -> MaybeAuto { let fragment = block.fragment(); - fragment.assign_replaced_width_if_necessary(parent_flow_width, None); + fragment.assign_replaced_inline_size_if_necessary(parent_flow_inline_size, None); // For replaced block flow, the rest of the constraint solving will - // take width to be specified as the value computed here. - Specified(fragment.content_width()) + // take inline-size to be specified as the value computed here. + Specified(fragment.content_inline_size()) } } -impl WidthAndMarginsComputer for FloatNonReplaced { +impl ISizeAndMarginsComputer for FloatNonReplaced { /// CSS Section 10.3.5 /// - /// If width is computed as 'auto', the used value is the 'shrink-to-fit' width. - fn solve_width_constraints(&self, + /// If inline-size is computed as 'auto', the used value is the 'shrink-to-fit' inline-size. + fn solve_inline_size_constraints(&self, block: &mut BlockFlow, - input: &WidthConstraintInput) - -> WidthConstraintSolution { - let (computed_width, left_margin, right_margin, available_width) = (input.computed_width, - input.left_margin, - input.right_margin, - input.available_width); - let margin_left = left_margin.specified_or_zero(); - let margin_right = right_margin.specified_or_zero(); - let available_width_float = available_width - margin_left - margin_right; - let shrink_to_fit = block.get_shrink_to_fit_width(available_width_float); - let width = computed_width.specified_or_default(shrink_to_fit); - debug!("assign_widths_float -- width: {}", width); - WidthConstraintSolution::new(width, margin_left, margin_right) + input: &ISizeConstraintInput) + -> ISizeConstraintSolution { + let (computed_inline_size, inline_start_margin, inline_end_margin, available_inline_size) = (input.computed_inline_size, + input.inline_start_margin, + input.inline_end_margin, + input.available_inline_size); + let margin_inline_start = inline_start_margin.specified_or_zero(); + let margin_inline_end = inline_end_margin.specified_or_zero(); + let available_inline_size_float = available_inline_size - margin_inline_start - margin_inline_end; + let shrink_to_fit = block.get_shrink_to_fit_inline_size(available_inline_size_float); + let inline_size = computed_inline_size.specified_or_default(shrink_to_fit); + debug!("assign_inline_sizes_float -- inline_size: {}", inline_size); + ISizeConstraintSolution::new(inline_size, margin_inline_start, margin_inline_end) } } -impl WidthAndMarginsComputer for FloatReplaced { +impl ISizeAndMarginsComputer for FloatReplaced { /// CSS Section 10.3.5 /// - /// If width is computed as 'auto', the used value is the 'shrink-to-fit' width. - fn solve_width_constraints(&self, _: &mut BlockFlow, input: &WidthConstraintInput) - -> WidthConstraintSolution { - let (computed_width, left_margin, right_margin) = (input.computed_width, - input.left_margin, - input.right_margin); - let margin_left = left_margin.specified_or_zero(); - let margin_right = right_margin.specified_or_zero(); - let width = match computed_width { + /// If inline-size is computed as 'auto', the used value is the 'shrink-to-fit' inline-size. + fn solve_inline_size_constraints(&self, _: &mut BlockFlow, input: &ISizeConstraintInput) + -> ISizeConstraintSolution { + let (computed_inline_size, inline_start_margin, inline_end_margin) = (input.computed_inline_size, + input.inline_start_margin, + input.inline_end_margin); + let margin_inline_start = inline_start_margin.specified_or_zero(); + let margin_inline_end = inline_end_margin.specified_or_zero(); + let inline_size = match computed_inline_size { Specified(w) => w, - Auto => fail!("FloatReplaced: width should have been computed by now") + Auto => fail!("FloatReplaced: inline_size should have been computed by now") }; - debug!("assign_widths_float -- width: {}", width); - WidthConstraintSolution::new(width, margin_left, margin_right) + debug!("assign_inline_sizes_float -- inline_size: {}", inline_size); + ISizeConstraintSolution::new(inline_size, margin_inline_start, margin_inline_end) } - /// Calculate used value of width just like we do for inline replaced elements. - fn initial_computed_width(&self, + /// Calculate used value of inline-size just like we do for inline replaced elements. + fn initial_computed_inline_size(&self, block: &mut BlockFlow, - parent_flow_width: Au, + parent_flow_inline_size: Au, _: &mut LayoutContext) -> MaybeAuto { let fragment = block.fragment(); - fragment.assign_replaced_width_if_necessary(parent_flow_width, None); + fragment.assign_replaced_inline_size_if_necessary(parent_flow_inline_size, None); // For replaced block flow, the rest of the constraint solving will - // take width to be specified as the value computed here. - Specified(fragment.content_width()) + // take inline-size to be specified as the value computed here. + Specified(fragment.content_inline_size()) } } -fn propagate_column_widths_to_child(kid: &mut Flow, +fn propagate_column_inline_sizes_to_child(kid: &mut Flow, child_index: uint, - content_width: Au, - column_widths: &[Au], - left_margin_edge: &mut Au) { - // If kid is table_rowgroup or table_row, the column widths info should be copied from its + content_inline_size: Au, + column_inline_sizes: &[Au], + inline_start_margin_edge: &mut Au) { + // If kid is table_rowgroup or table_row, the column inline-sizes info should be copied from its // parent. // // FIXME(pcwalton): This seems inefficient. Reference count it instead? - let width = if kid.is_table() || kid.is_table_rowgroup() || kid.is_table_row() { - *kid.col_widths() = column_widths.iter().map(|&x| x).collect(); + let inline_size = if kid.is_table() || kid.is_table_rowgroup() || kid.is_table_row() { + *kid.col_inline_sizes() = column_inline_sizes.iter().map(|&x| x).collect(); - // Width of kid flow is our content width. - content_width + // ISize of kid flow is our content inline-size. + content_inline_size } else if kid.is_table_cell() { - // If kid is table_cell, the x offset and width for each cell should be - // calculated from parent's column widths info. - *left_margin_edge = if child_index == 0 { + // If kid is table_cell, the x offset and inline-size for each cell should be + // calculated from parent's column inline-sizes info. + *inline_start_margin_edge = if child_index == 0 { Au(0) } else { - *left_margin_edge + column_widths[child_index - 1] + *inline_start_margin_edge + column_inline_sizes[child_index - 1] }; - column_widths[child_index] + column_inline_sizes[child_index] } else { - // Width of kid flow is our content width. - content_width + // ISize of kid flow is our content inline-size. + content_inline_size }; let kid_base = flow::mut_base(kid); - kid_base.position.origin.x = *left_margin_edge; - kid_base.position.size.width = width; + kid_base.position.start.i = *inline_start_margin_edge; + kid_base.position.size.inline = inline_size; } diff --git a/src/components/layout/construct.rs b/src/components/layout/construct.rs index ffce4986baa..113e4a28b60 100644 --- a/src/components/layout/construct.rs +++ b/src/components/layout/construct.rs @@ -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; 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) } } } diff --git a/src/components/layout/context.rs b/src/components/layout/context.rs index fdd6dec0254..9fca5632659 100644 --- a/src/components/layout/context.rs +++ b/src/components/layout/context.rs @@ -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; diff --git a/src/components/layout/floats.rs b/src/components/layout/floats.rs index 15aae932b63..94ad8c940f6 100644 --- a/src/components/layout/floats.rs +++ b/src/components/layout/floats.rs @@ -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, + bounds: LogicalRect, /// 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, - /// 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, - /// The minimum top of the float, as determined by earlier elements. + pub size: LogicalSize, + /// 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, + offset: LogicalSize, + 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) { + pub fn translate(&mut self, delta: LogicalSize) { self.offset = self.offset + delta } /// Returns the position of the last float in flow coordinates. - pub fn last_float_pos(&self) -> Option> { + pub fn last_float_pos(&self) -> Option> { 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> { + /// 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> { 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 { + /// 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 { 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 { - 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 { + 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); } _ => {} } diff --git a/src/components/layout/flow.rs b/src/components/layout/flow.rs index 71924bf13b0..76eb5a39274 100644 --- a/src/components/layout/flow.rs +++ b/src/components/layout/flow.rs @@ -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 { - 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 { + 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 { - 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 { + 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 { - 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 { + 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 { + fn generated_containing_block_rect(&self) -> LogicalRect { 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, /// Static y offsets of all descendants from the start of this flow box. - pub static_y_offsets: Vec, + pub static_b_offsets: Vec, } 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, 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, + pub relative_containing_block_size: LogicalSize, /// The position of the absolute containing block. - pub absolute_containing_block_position: Point2D, + pub absolute_containing_block_position: LogicalPoint, /// 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, + pub position: LogicalRect, /// 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, + pub overflow: LogicalRect, /// 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, + pub abs_position: LogicalPoint, /// 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 { + pub fn generated_containing_block_rect(&mut self) -> LogicalRect { match self.link { None => fail!("haven't done it"), Some(ref mut link) => link.get_mut().generated_containing_block_rect(), diff --git a/src/components/layout/fragment.rs b/src/components/layout/fragment.rs index d132cd47a9b..f495d5d1e0e 100644 --- a/src/components/layout/fragment.rs +++ b/src/components/layout/fragment.rs @@ -13,7 +13,7 @@ use floats::{ClearBoth, ClearLeft, ClearRight, ClearType}; use flow::Flow; use flow; use inline::{InlineFragmentContext, InlineMetrics}; -use model::{Auto, IntrinsicWidths, MaybeAuto, Specified, specified}; +use model::{Auto, IntrinsicISizes, MaybeAuto, Specified, specified}; use model; use text; use util::{OpaqueNodeMethods, ToGfxColor}; @@ -37,13 +37,13 @@ use servo_net::image::holder::ImageHolder; use servo_net::local_image_cache::LocalImageCache; use servo_util::geometry::Au; use servo_util::geometry; +use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, LogicalMargin}; use servo_util::range::*; use servo_util::namespace; use servo_util::smallvec::SmallVec; use servo_util::str::is_whitespace; use std::fmt; use std::from_str::FromStr; -use std::iter::AdditiveIterator; use std::mem; use std::num::Zero; use style::{ComputedValues, TElement, TNode, cascade_anonymous}; @@ -83,14 +83,14 @@ pub struct Fragment { /// The position of this fragment relative to its owning flow. /// The size includes padding and border, but not margin. - pub border_box: Rect, + pub border_box: LogicalRect, /// The sum of border and padding; i.e. the distance from the edge of the border box to the /// content edge of the fragment. - pub border_padding: SideOffsets2D, + pub border_padding: LogicalMargin, /// The margin of the content box. - pub margin: SideOffsets2D, + pub margin: LogicalMargin, /// Info specific to the kind of fragment. Keep this enum small. pub specific: SpecificFragmentInfo, @@ -121,10 +121,11 @@ pub enum SpecificFragmentInfo { pub struct ImageFragmentInfo { /// The image held within this fragment. pub image: ImageHolder, - pub computed_width: Option, - pub computed_height: Option, - pub dom_width: Option, - pub dom_height: Option, + pub computed_inline_size: Option, + pub computed_block_size: Option, + pub dom_inline_size: Option, + pub dom_block_size: Option, + pub writing_mode_is_vertical: bool, } impl ImageFragmentInfo { @@ -144,34 +145,49 @@ impl ImageFragmentInfo { }).and_then(|pixels| Some(Au::from_px(pixels))) } + let is_vertical = node.style().writing_mode.is_vertical(); + let dom_width = convert_length(node, "width"); + let dom_height = convert_length(node, "height"); ImageFragmentInfo { image: ImageHolder::new(image_url, local_image_cache), - computed_width: None, - computed_height: None, - dom_width: convert_length(node,"width"), - dom_height: convert_length(node,"height"), + computed_inline_size: None, + computed_block_size: None, + dom_inline_size: if is_vertical { dom_height } else { dom_width }, + dom_block_size: if is_vertical { dom_width } else { dom_height }, + writing_mode_is_vertical: is_vertical, } } - /// Returns the calculated width of the image, accounting for the width attribute. - pub fn computed_width(&self) -> Au { - self.computed_width.expect("image width is not computed yet!") + /// Returns the calculated inline-size of the image, accounting for the inline-size attribute. + pub fn computed_inline_size(&self) -> Au { + self.computed_inline_size.expect("image inline_size is not computed yet!") } - /// Returns the original width of the image. - pub fn image_width(&mut self) -> Au { - let image_ref = &mut self.image; - Au::from_px(image_ref.get_size().unwrap_or(Size2D(0,0)).width) + /// Returns the calculated block-size of the image, accounting for the block-size attribute. + pub fn computed_block_size(&self) -> Au { + self.computed_block_size.expect("image block_size is not computed yet!") } - // Return used value for width or height. + /// Returns the original inline-size of the image. + pub fn image_inline_size(&mut self) -> Au { + let size = self.image.get_size().unwrap_or(Size2D::zero()); + Au::from_px(if self.writing_mode_is_vertical { size.height } else { size.width }) + } + + /// Returns the original block-size of the image. + pub fn image_block_size(&mut self) -> Au { + let size = self.image.get_size().unwrap_or(Size2D::zero()); + Au::from_px(if self.writing_mode_is_vertical { size.width } else { size.height }) + } + + // Return used value for inline-size or block-size. // - // `dom_length`: width or height as specified in the `img` tag. - // `style_length`: width as given in the CSS + // `dom_length`: inline-size or block-size as specified in the `img` tag. + // `style_length`: inline-size as given in the CSS pub fn style_length(style_length: LengthOrPercentageOrAuto, dom_length: Option, - container_width: Au) -> MaybeAuto { - match (MaybeAuto::from_style(style_length,container_width),dom_length) { + container_inline_size: Au) -> MaybeAuto { + match (MaybeAuto::from_style(style_length,container_inline_size),dom_length) { (Specified(length),_) => { Specified(length) }, @@ -183,19 +199,6 @@ impl ImageFragmentInfo { } } } - /// Returns the calculated height of the image, accounting for the height attribute. - pub fn computed_height(&self) -> Au { - match self.computed_height { - Some(height) => height, - None => fail!("image height is not computed yet!"), - } - } - - /// Returns the original height of the image. - pub fn image_height(&mut self) -> Au { - let image_ref = &mut self.image; - Au::from_px(image_ref.get_size().unwrap_or(Size2D(0,0)).height) - } } /// A fragment that represents an inline frame (iframe). This stores the pipeline ID so that the size @@ -247,20 +250,20 @@ pub struct SplitInfo { // TODO(bjz): this should only need to be a single character index, but both values are // currently needed for splitting in the `inline::try_append_*` functions. pub range: Range, - pub width: Au, + pub inline_size: Au, } impl SplitInfo { fn new(range: Range, info: &ScannedTextFragmentInfo) -> SplitInfo { SplitInfo { range: range, - width: info.run.advance_for_range(&range), + inline_size: info.run.advance_for_range(&range), } } } /// Data for an unscanned text fragment. Unscanned text fragments are the results of flow construction that -/// have not yet had their width determined. +/// have not yet had their inline-size determined. #[deriving(Clone)] pub struct UnscannedTextFragmentInfo { /// The text inside the fragment. @@ -317,12 +320,14 @@ impl Fragment { /// /// * `node`: The node to create a fragment for. pub fn new(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode) -> Fragment { + let style = node.style().clone(); + let writing_mode = style.writing_mode; Fragment { node: OpaqueNodeMethods::from_thread_safe_layout_node(node), - style: node.style().clone(), - border_box: Rect::zero(), - border_padding: Zero::zero(), - margin: Zero::zero(), + style: style, + border_box: LogicalRect::zero(writing_mode), + border_padding: LogicalMargin::zero(writing_mode), + margin: LogicalMargin::zero(writing_mode), specific: constructor.build_specific_fragment_info_for_node(node), new_line_pos: vec!(), } @@ -330,12 +335,14 @@ impl Fragment { /// Constructs a new `Fragment` instance from a specific info. pub fn new_from_specific_info(node: &ThreadSafeLayoutNode, specific: SpecificFragmentInfo) -> Fragment { + let style = node.style().clone(); + let writing_mode = style.writing_mode; Fragment { node: OpaqueNodeMethods::from_thread_safe_layout_node(node), - style: node.style().clone(), - border_box: Rect::zero(), - border_padding: Zero::zero(), - margin: Zero::zero(), + style: style, + border_box: LogicalRect::zero(writing_mode), + border_padding: LogicalMargin::zero(writing_mode), + margin: LogicalMargin::zero(writing_mode), specific: specific, new_line_pos: vec!(), } @@ -353,12 +360,13 @@ impl Fragment { // Anonymous table fragments, TableRowFragment and TableCellFragment, are generated around `Foo`, but it shouldn't inherit the border. let node_style = cascade_anonymous(&**node.style()); + let writing_mode = node_style.writing_mode; Fragment { node: OpaqueNodeMethods::from_thread_safe_layout_node(node), style: Arc::new(node_style), - border_box: Rect::zero(), - border_padding: Zero::zero(), - margin: Zero::zero(), + border_box: LogicalRect::zero(writing_mode), + border_padding: LogicalMargin::zero(writing_mode), + margin: LogicalMargin::zero(writing_mode), specific: specific, new_line_pos: vec!(), } @@ -369,12 +377,13 @@ impl Fragment { style: Arc, specific: SpecificFragmentInfo) -> Fragment { + let writing_mode = style.writing_mode; Fragment { node: node, style: style, - border_box: Rect::zero(), - border_padding: Zero::zero(), - margin: Zero::zero(), + border_box: LogicalRect::zero(writing_mode), + border_padding: LogicalMargin::zero(writing_mode), + margin: LogicalMargin::zero(writing_mode), specific: specific, new_line_pos: vec!(), } @@ -388,11 +397,12 @@ impl Fragment { /// Transforms this fragment into another fragment of the given type, with the given size, preserving all /// the other data. - pub fn transform(&self, size: Size2D, specific: SpecificFragmentInfo) -> Fragment { + pub fn transform(&self, size: LogicalSize, specific: SpecificFragmentInfo) -> Fragment { Fragment { node: self.node, style: self.style.clone(), - border_box: Rect(self.border_box.origin, size), + border_box: LogicalRect::from_point_size( + self.style.writing_mode, self.border_box.start, size), border_padding: self.border_padding, margin: self.margin, specific: specific, @@ -400,9 +410,9 @@ impl Fragment { } } - /// Uses the style only to estimate the intrinsic widths. These may be modified for text or + /// Uses the style only to estimate the intrinsic inline-sizes. These may be modified for text or /// replaced elements. - fn style_specified_intrinsic_width(&self) -> IntrinsicWidths { + fn style_specified_intrinsic_inline_size(&self) -> IntrinsicISizes { let (use_margins, use_padding) = match self.specific { GenericFragment | IframeFragment(_) | ImageFragment(_) => (true, true), TableFragment | TableCellFragment => (false, true), @@ -410,36 +420,38 @@ impl Fragment { TableRowFragment => (false, false), ScannedTextFragment(_) | TableColumnFragment(_) | UnscannedTextFragment(_) => { // Styles are irrelevant for these kinds of fragments. - return IntrinsicWidths::new() + return IntrinsicISizes::new() } }; let style = self.style(); - let width = MaybeAuto::from_style(style.get_box().width, Au::new(0)).specified_or_zero(); + let inline_size = MaybeAuto::from_style(style.content_inline_size(), Au::new(0)).specified_or_zero(); - let (margin_left, margin_right) = if use_margins { - (MaybeAuto::from_style(style.get_margin().margin_left, Au(0)).specified_or_zero(), - MaybeAuto::from_style(style.get_margin().margin_right, Au(0)).specified_or_zero()) + let margin = style.logical_margin(); + let (margin_inline_start, margin_inline_end) = if use_margins { + (MaybeAuto::from_style(margin.inline_start, Au(0)).specified_or_zero(), + MaybeAuto::from_style(margin.inline_end, Au(0)).specified_or_zero()) } else { (Au(0), Au(0)) }; - let (padding_left, padding_right) = if use_padding { - (model::specified(style.get_padding().padding_left, Au(0)), - model::specified(style.get_padding().padding_right, Au(0))) + let padding = style.logical_padding(); + let (padding_inline_start, padding_inline_end) = if use_padding { + (model::specified(padding.inline_start, Au(0)), + model::specified(padding.inline_end, Au(0))) } else { (Au(0), Au(0)) }; // FIXME(#2261, pcwalton): This won't work well for inlines: is this OK? let border = self.border_width(None); - let surround_width = margin_left + margin_right + padding_left + padding_right + - border.horizontal(); + let surround_inline_size = margin_inline_start + margin_inline_end + padding_inline_start + padding_inline_end + + border.inline_start_end(); - IntrinsicWidths { - minimum_width: width, - preferred_width: width, - surround_width: surround_width, + IntrinsicISizes { + minimum_inline_size: inline_size, + preferred_inline_size: inline_size, + surround_inline_size: surround_inline_size, } } @@ -447,60 +459,58 @@ impl Fragment { text::line_height_from_style(self.style(), font_size) } - /// Returns the sum of the widths of all the borders of this fragment. This is private because - /// it should only be called during intrinsic width computation or computation of + /// Returns the sum of the inline-sizes of all the borders of this fragment. This is private because + /// it should only be called during intrinsic inline-size computation or computation of /// `border_padding`. Other consumers of this information should simply consult that field. #[inline] fn border_width(&self, inline_fragment_context: Option) - -> SideOffsets2D { + -> LogicalMargin { match inline_fragment_context { - None => model::border_from_style(self.style()), + None => self.style().logical_border_width(), Some(inline_fragment_context) => { - inline_fragment_context.ranges().map(|range| range.border()).sum() + let zero = LogicalMargin::zero(self.style.writing_mode); + inline_fragment_context.ranges().fold(zero, |acc, range| acc + range.border()) } } } - /// Computes the border, padding, and vertical margins from the containing block width and the + /// Computes the border, padding, and vertical margins from the containing block inline-size and the /// style. After this call, the `border_padding` and the vertical direction of the `margin` /// field will be correct. pub fn compute_border_padding_margins(&mut self, - containing_block_width: Au, + containing_block_inline_size: Au, inline_fragment_context: Option) { // Compute vertical margins. Note that this value will be ignored by layout if the style // specifies `auto`. match self.specific { TableFragment | TableCellFragment | TableRowFragment | TableColumnFragment(_) => { - self.margin.top = Au(0); - self.margin.bottom = Au(0) + self.margin.block_start = Au(0); + self.margin.block_end = Au(0) } _ => { - // NB: Percentages are relative to containing block width (not height) per CSS 2.1. - self.margin.top = - MaybeAuto::from_style(self.style().get_margin().margin_top, - containing_block_width).specified_or_zero(); - self.margin.bottom = - MaybeAuto::from_style(self.style().get_margin().margin_bottom, - containing_block_width).specified_or_zero() + // NB: Percentages are relative to containing block inline-size (not block-size) per CSS 2.1. + let margin = self.style().logical_margin(); + self.margin.block_start = MaybeAuto::from_style(margin.block_start, containing_block_inline_size) + .specified_or_zero(); + self.margin.block_end = MaybeAuto::from_style(margin.block_end, containing_block_inline_size) + .specified_or_zero() } } // Compute border. - let border = match inline_fragment_context { - None => model::border_from_style(self.style()), - Some(inline_fragment_context) => { - inline_fragment_context.ranges().map(|range| range.border()).sum() - } - }; + let border = self.border_width(inline_fragment_context); // Compute padding. let padding = match self.specific { - TableColumnFragment(_) | TableRowFragment | TableWrapperFragment => Zero::zero(), + TableColumnFragment(_) | TableRowFragment | + TableWrapperFragment => LogicalMargin::zero(self.style.writing_mode), _ => { match inline_fragment_context { - None => model::padding_from_style(self.style(), containing_block_width), + None => model::padding_from_style(self.style(), containing_block_inline_size), Some(inline_fragment_context) => { - inline_fragment_context.ranges().map(|range| range.padding()).sum() + let zero = LogicalMargin::zero(self.style.writing_mode); + inline_fragment_context.ranges() + .fold(zero, |acc, range| acc + range.padding()) } } } @@ -511,57 +521,41 @@ impl Fragment { // Return offset from original position because of `position: relative`. pub fn relative_position(&self, - container_block_size: &Size2D, + containing_block_size: &LogicalSize, inline_fragment_context: Option) - -> Point2D { - fn left_right(style: &ComputedValues, block_width: Au) -> Au { - // TODO(ksh8281) : consider RTL(right-to-left) culture - match (style.get_positionoffsets().left, style.get_positionoffsets().right) { - (LPA_Auto, _) => { - -MaybeAuto::from_style(style.get_positionoffsets().right, block_width) - .specified_or_zero() - } - (_, _) => { - MaybeAuto::from_style(style.get_positionoffsets().left, block_width) - .specified_or_zero() - } - } - } - - fn top_bottom(style: &ComputedValues,block_height: Au) -> Au { - match (style.get_positionoffsets().top, style.get_positionoffsets().bottom) { - (LPA_Auto, _) => { - -MaybeAuto::from_style(style.get_positionoffsets().bottom, block_height) - .specified_or_zero() - } - (_, _) => { - MaybeAuto::from_style(style.get_positionoffsets().top, block_height) - .specified_or_zero() - } - } + -> LogicalSize { + fn from_style(style: &ComputedValues, container_size: &LogicalSize) + -> LogicalSize { + let offsets = style.logical_position(); + let offset_i = if offsets.inline_start != LPA_Auto { + MaybeAuto::from_style(offsets.inline_start, container_size.inline).specified_or_zero() + } else { + -MaybeAuto::from_style(offsets.inline_end, container_size.inline).specified_or_zero() + }; + let offset_b = if offsets.block_start != LPA_Auto { + MaybeAuto::from_style(offsets.block_start, container_size.inline).specified_or_zero() + } else { + -MaybeAuto::from_style(offsets.block_end, container_size.inline).specified_or_zero() + }; + LogicalSize::new(style.writing_mode, offset_i, offset_b) } // Go over the ancestor fragments and add all relative offsets (if any). - let mut rel_pos: Point2D = Zero::zero(); + let mut rel_pos = LogicalSize::zero(self.style.writing_mode); match inline_fragment_context { None => { if self.style().get_box().position == position::relative { - rel_pos.x = rel_pos.x + left_right(self.style(), container_block_size.width); - rel_pos.y = rel_pos.y + top_bottom(self.style(), container_block_size.height); + rel_pos = rel_pos + from_style(self.style(), containing_block_size); } } Some(inline_fragment_context) => { for range in inline_fragment_context.ranges() { if range.style.get_box().position == position::relative { - rel_pos.x = rel_pos.x + left_right(&*range.style, - container_block_size.width); - rel_pos.y = rel_pos.y + top_bottom(&*range.style, - container_block_size.height); + rel_pos = rel_pos + from_style(&*range.style, containing_block_size); } } }, } - rel_pos } @@ -614,16 +608,16 @@ impl Fragment { self.style().get_text().text_decoration } - /// Returns the left offset from margin edge to content edge. + /// Returns the inline-start offset from margin edge to content edge. /// /// FIXME(#2262, pcwalton): I think this method is pretty bogus, because it won't work for /// inlines. - pub fn left_offset(&self) -> Au { + pub fn inline_start_offset(&self) -> Au { match self.specific { - TableWrapperFragment => self.margin.left, - TableFragment | TableCellFragment | TableRowFragment => self.border_padding.left, + TableWrapperFragment => self.margin.inline_start, + TableFragment | TableCellFragment | TableRowFragment => self.border_padding.inline_start, TableColumnFragment(_) => Au(0), - _ => self.margin.left + self.border_padding.left, + _ => self.margin.inline_start + self.border_padding.inline_start, } } @@ -751,7 +745,7 @@ impl Fragment { Option) { // Fast path. let border = self.border_width(inline_fragment_context); - if border == Zero::zero() { + if border.is_zero() { return } @@ -764,7 +758,7 @@ impl Fragment { // Append the border to the display list. let border_display_item = box BorderDisplayItem { base: BaseDisplayItem::new(*abs_bounds, self.node, level), - border: border, + border: border.to_physical(self.style.writing_mode), color: SideOffsets2D::new(top_color.to_gfx_color(), right_color.to_gfx_color(), bottom_color.to_gfx_color(), @@ -780,17 +774,20 @@ impl Fragment { fn build_debug_borders_around_text_fragments(&self, display_list: &mut DisplayList, - flow_origin: Point2D, + flow_origin: LogicalPoint, text_fragment: &ScannedTextFragmentInfo) { - let fragment_bounds = self.border_box; - let absolute_fragment_bounds = fragment_bounds.translate(&flow_origin); + let mut fragment_bounds = self.border_box.clone(); + fragment_bounds.start.i = fragment_bounds.start.i + flow_origin.i; + fragment_bounds.start.b = fragment_bounds.start.b + flow_origin.b; + // FIXME(#2795): Get the real container size + let container_size = Size2D::zero(); + let absolute_fragment_bounds = fragment_bounds.to_physical( + self.style.writing_mode, container_size); // Compute the text fragment bounds and draw a border surrounding them. - let debug_border = SideOffsets2D::new_all_same(Au::from_px(1)); - let border_display_item = box BorderDisplayItem { base: BaseDisplayItem::new(absolute_fragment_bounds, self.node, ContentStackingLevel), - border: debug_border, + border: SideOffsets2D::new_all_same(Au::from_px(1)), color: SideOffsets2D::new_all_same(rgb(0, 0, 200)), style: SideOffsets2D::new_all_same(border_style::solid) }; @@ -798,8 +795,13 @@ impl Fragment { // Draw a rectangle representing the baselines. let ascent = text_fragment.run.ascent(); - let baseline = Rect(absolute_fragment_bounds.origin + Point2D(Au(0), ascent), - Size2D(absolute_fragment_bounds.size.width, Au(0))); + let baseline = LogicalRect::new( + self.style.writing_mode, + fragment_bounds.start.i, + fragment_bounds.start.b + ascent, + fragment_bounds.size.inline, + Au(0) + ).to_physical(self.style.writing_mode, container_size); let line_display_item = box LineDisplayItem { base: BaseDisplayItem::new(baseline, self.node, ContentStackingLevel), @@ -811,16 +813,19 @@ impl Fragment { fn build_debug_borders_around_fragment(&self, display_list: &mut DisplayList, - flow_origin: Point2D) { - let fragment_bounds = self.border_box; - let absolute_fragment_bounds = fragment_bounds.translate(&flow_origin); + flow_origin: LogicalPoint) { + let mut fragment_bounds = self.border_box.clone(); + fragment_bounds.start.i = fragment_bounds.start.i + flow_origin.i; + fragment_bounds.start.b = fragment_bounds.start.b + flow_origin.b; + // FIXME(#2795): Get the real container size + let container_size = Size2D::zero(); + let absolute_fragment_bounds = fragment_bounds.to_physical( + self.style.writing_mode, container_size); // This prints a debug border around the border of this fragment. - let debug_border = SideOffsets2D::new_all_same(Au::from_px(1)); - let border_display_item = box BorderDisplayItem { base: BaseDisplayItem::new(absolute_fragment_bounds, self.node, ContentStackingLevel), - border: debug_border, + border: SideOffsets2D::new_all_same(Au::from_px(1)), color: SideOffsets2D::new_all_same(rgb(0, 0, 200)), style: SideOffsets2D::new_all_same(border_style::solid) }; @@ -838,15 +843,20 @@ impl Fragment { pub fn build_display_list(&self, display_list: &mut DisplayList, layout_context: &LayoutContext, - flow_origin: Point2D, + flow_origin: LogicalPoint, background_and_border_level: BackgroundAndBorderLevel, inline_fragment_context: Option) -> ChildDisplayListAccumulator { // Fragment position wrt to the owning flow. - let fragment_bounds = self.border_box; - let absolute_fragment_bounds = fragment_bounds.translate(&flow_origin); + let mut fragment_bounds = self.border_box.clone(); + fragment_bounds.start.i = fragment_bounds.start.i + flow_origin.i; + fragment_bounds.start.b = fragment_bounds.start.b + flow_origin.b; + // FIXME(#2795): Get the real container size + let container_size = Size2D::zero(); + let absolute_fragment_bounds = fragment_bounds.to_physical( + self.style.writing_mode, container_size); debug!("Fragment::build_display_list at rel={}, abs={}: {}", - fragment_bounds, + self.border_box, absolute_fragment_bounds, self); debug!("Fragment::build_display_list: dirty={}, flow_origin={}", @@ -911,8 +921,14 @@ impl Fragment { }; let mut bounds = absolute_fragment_bounds.clone(); - bounds.origin.x = bounds.origin.x + self.border_padding.left; - bounds.size.width = bounds.size.width - self.border_padding.horizontal(); + let mut border_padding = self.border_padding.clone(); + border_padding.block_start = Au::new(0); + border_padding.block_end = Au::new(0); + let border_padding = border_padding.to_physical(self.style.writing_mode); + bounds.origin.x = bounds.origin.x + border_padding.left; + bounds.origin.y = bounds.origin.y + border_padding.top; + bounds.size.width = bounds.size.width - border_padding.horizontal(); + bounds.size.height = bounds.size.height - border_padding.vertical(); // Create the text fragment. let text_display_item = box TextDisplayItem { @@ -940,10 +956,11 @@ impl Fragment { }, ImageFragment(_) => { let mut bounds = absolute_fragment_bounds.clone(); - bounds.origin.x = bounds.origin.x + self.border_padding.left; - bounds.origin.y = bounds.origin.y + self.border_padding.top; - bounds.size.width = bounds.size.width - self.border_padding.horizontal(); - bounds.size.height = bounds.size.height - self.border_padding.vertical(); + let border_padding = self.border_padding.to_physical(self.style.writing_mode); + bounds.origin.x = bounds.origin.x + border_padding.left; + bounds.origin.y = bounds.origin.y + border_padding.top; + bounds.size.width = bounds.size.width - border_padding.horizontal(); + bounds.size.height = bounds.size.height - border_padding.vertical(); match self.specific { ImageFragment(ref image_fragment) => { @@ -986,7 +1003,7 @@ impl Fragment { // problematic if iframes are outside the area we're computing the display list for, since // they won't be able to reflow at all until the user scrolls to them. Perhaps we should // separate this into two parts: first we should send the size only to the constellation - // once that's computed during assign-heights, and second we should should send the origin + // once that's computed during assign-block-sizes, and second we should should send the origin // to the constellation here during display list construction. This should work because // layout for the iframe only needs to know size, and origin is only relevant if the // iframe is actually going to be displayed. @@ -1000,31 +1017,31 @@ impl Fragment { accumulator } - /// Returns the intrinsic widths of this fragment. - pub fn intrinsic_widths(&mut self, inline_fragment_context: Option) - -> IntrinsicWidths { - let mut result = self.style_specified_intrinsic_width(); + /// Returns the intrinsic inline-sizes of this fragment. + pub fn intrinsic_inline_sizes(&mut self, inline_fragment_context: Option) + -> IntrinsicISizes { + let mut result = self.style_specified_intrinsic_inline_size(); match self.specific { GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | TableColumnFragment(_) | TableRowFragment | TableWrapperFragment => {} ImageFragment(ref mut image_fragment_info) => { - let image_width = image_fragment_info.image_width(); - result.minimum_width = geometry::max(result.minimum_width, image_width); - result.preferred_width = geometry::max(result.preferred_width, image_width); + let image_inline_size = image_fragment_info.image_inline_size(); + result.minimum_inline_size = geometry::max(result.minimum_inline_size, image_inline_size); + result.preferred_inline_size = geometry::max(result.preferred_inline_size, image_inline_size); } ScannedTextFragment(ref text_fragment_info) => { let range = &text_fragment_info.range; - let min_line_width = text_fragment_info.run.min_width_for_range(range); + let min_line_inline_size = text_fragment_info.run.min_width_for_range(range); - let mut max_line_width = Au::new(0); + let mut max_line_inline_size = Au::new(0); for line_range in text_fragment_info.run.iter_natural_lines_for_range(range) { let line_metrics = text_fragment_info.run.metrics_for_range(&line_range); - max_line_width = Au::max(max_line_width, line_metrics.advance_width); + max_line_inline_size = Au::max(max_line_inline_size, line_metrics.advance_width); } - result.minimum_width = geometry::max(result.minimum_width, min_line_width); - result.preferred_width = geometry::max(result.preferred_width, max_line_width); + result.minimum_inline_size = geometry::max(result.minimum_inline_size, min_line_inline_size); + result.preferred_inline_size = geometry::max(result.preferred_inline_size, max_line_inline_size); } UnscannedTextFragment(..) => fail!("Unscanned text fragments should have been scanned by now!"), } @@ -1034,10 +1051,10 @@ impl Fragment { None => {} Some(context) => { for range in context.ranges() { - let border_width = range.border().horizontal(); - let padding_width = range.padding().horizontal(); - result.minimum_width = result.minimum_width + border_width + padding_width; - result.preferred_width = result.preferred_width + border_width + padding_width; + let border_width = range.border().inline_start_end(); + let padding_inline_size = range.padding().inline_start_end(); + result.minimum_inline_size = result.minimum_inline_size + border_width + padding_inline_size; + result.preferred_inline_size = result.preferred_inline_size + border_width + padding_inline_size; } } } @@ -1047,33 +1064,33 @@ impl Fragment { /// TODO: What exactly does this function return? Why is it Au(0) for GenericFragment? - pub fn content_width(&self) -> Au { + pub fn content_inline_size(&self) -> Au { match self.specific { GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | TableRowFragment | TableWrapperFragment => Au(0), ImageFragment(ref image_fragment_info) => { - image_fragment_info.computed_width() + image_fragment_info.computed_inline_size() } ScannedTextFragment(ref text_fragment_info) => { let (range, run) = (&text_fragment_info.range, &text_fragment_info.run); let text_bounds = run.metrics_for_range(range).bounding_box; text_bounds.size.width } - TableColumnFragment(_) => fail!("Table column fragments do not have width"), + TableColumnFragment(_) => fail!("Table column fragments do not have inline_size"), UnscannedTextFragment(_) => fail!("Unscanned text fragments should have been scanned by now!"), } } - /// Returns, and computes, the height of this fragment. - pub fn content_height(&self) -> Au { + /// Returns, and computes, the block-size of this fragment. + pub fn content_block_size(&self) -> Au { match self.specific { GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | TableRowFragment | TableWrapperFragment => Au(0), ImageFragment(ref image_fragment_info) => { - image_fragment_info.computed_height() + image_fragment_info.computed_block_size() } ScannedTextFragment(ref text_fragment_info) => { - // Compute the height based on the line-height and font size. + // Compute the block-size based on the line-block-size and font size. // // FIXME(pcwalton): Shouldn't we use the value of the `font-size` property below // instead of the bounding box of the text run? @@ -1082,7 +1099,7 @@ impl Fragment { let em_size = text_bounds.size.height; self.calculate_line_height(em_size) } - TableColumnFragment(_) => fail!("Table column fragments do not have height"), + TableColumnFragment(_) => fail!("Table column fragments do not have block_size"), UnscannedTextFragment(_) => fail!("Unscanned text fragments should have been scanned by now!"), } } @@ -1092,13 +1109,14 @@ impl Fragment { /// This is marked `#[inline]` because it is frequently called when only one or two of the /// values are needed and that will save computation. #[inline] - pub fn content_box(&self) -> Rect { - Rect { - origin: Point2D(self.border_box.origin.x + self.border_padding.left, - self.border_box.origin.y + self.border_padding.top), - size: Size2D(self.border_box.size.width - self.border_padding.horizontal(), - self.border_box.size.height - self.border_padding.vertical()), - } + pub fn content_box(&self) -> LogicalRect { + LogicalRect::new( + self.style.writing_mode, + self.border_box.start.i + self.border_padding.inline_start, + self.border_box.start.b + self.border_padding.block_start, + self.border_box.size.inline - self.border_padding.inline_start_end(), + self.border_box.size.block - self.border_padding.block_start_end(), + ) } /// Find the split of a fragment that includes a new-line character. @@ -1120,101 +1138,101 @@ impl Fragment { let mut new_line_pos = self.new_line_pos.clone(); let cur_new_line_pos = new_line_pos.shift().unwrap(); - let left_range = Range::new(text_fragment_info.range.begin(), cur_new_line_pos); - let right_range = Range::new(text_fragment_info.range.begin() + cur_new_line_pos + CharIndex(1), + let inline_start_range = Range::new(text_fragment_info.range.begin(), cur_new_line_pos); + let inline_end_range = Range::new(text_fragment_info.range.begin() + cur_new_line_pos + CharIndex(1), text_fragment_info.range.length() - (cur_new_line_pos + CharIndex(1))); - // Left fragment is for left text of first founded new-line character. - let left_fragment = SplitInfo::new(left_range, text_fragment_info); + // Left fragment is for inline-start text of first founded new-line character. + let inline_start_fragment = SplitInfo::new(inline_start_range, text_fragment_info); - // Right fragment is for right text of first founded new-line character. - let right_fragment = if right_range.length() > CharIndex(0) { - Some(SplitInfo::new(right_range, text_fragment_info)) + // Right fragment is for inline-end text of first founded new-line character. + let inline_end_fragment = if inline_end_range.length() > CharIndex(0) { + Some(SplitInfo::new(inline_end_range, text_fragment_info)) } else { None }; - Some((left_fragment, right_fragment, text_fragment_info.run.clone())) + Some((inline_start_fragment, inline_end_fragment, text_fragment_info.run.clone())) } } } - /// Attempts to find the split positions of a text fragment so that its width is - /// no more than `max_width`. + /// Attempts to find the split positions of a text fragment so that its inline-size is + /// no more than `max_inline-size`. /// /// A return value of `None` indicates that the fragment could not be split. - /// Otherwise the information pertaining to the split is returned. The left - /// and right split information are both optional due to the possibility of + /// Otherwise the information pertaining to the split is returned. The inline-start + /// and inline-end split information are both optional due to the possibility of /// them being whitespace. // // TODO(bjz): The text run should be removed in the future, but it is currently needed for // the current method of fragment splitting in the `inline::try_append_*` functions. - pub fn find_split_info_for_width(&self, start: CharIndex, max_width: Au, starts_line: bool) + pub fn find_split_info_for_inline_size(&self, start: CharIndex, max_inline_size: Au, starts_line: bool) -> Option<(Option, Option, Arc> /* TODO(bjz): remove */)> { match self.specific { GenericFragment | IframeFragment(_) | ImageFragment(_) | TableFragment | TableCellFragment | TableRowFragment | TableWrapperFragment => None, - TableColumnFragment(_) => fail!("Table column fragments do not have width"), + TableColumnFragment(_) => fail!("Table column fragments do not have inline_size"), UnscannedTextFragment(_) => fail!("Unscanned text fragments should have been scanned by now!"), ScannedTextFragment(ref text_fragment_info) => { let mut pieces_processed_count: uint = 0; - let mut remaining_width: Au = max_width; - let mut left_range = Range::new(text_fragment_info.range.begin() + start, CharIndex(0)); - let mut right_range: Option> = None; + let mut remaining_inline_size: Au = max_inline_size; + let mut inline_start_range = Range::new(text_fragment_info.range.begin() + start, CharIndex(0)); + let mut inline_end_range: Option> = None; - debug!("split_to_width: splitting text fragment (strlen={}, range={}, avail_width={})", + debug!("split_to_inline_size: splitting text fragment (strlen={}, range={}, avail_inline_size={})", text_fragment_info.run.text.len(), text_fragment_info.range, - max_width); + max_inline_size); for (glyphs, offset, slice_range) in text_fragment_info.run.iter_slices_for_range( &text_fragment_info.range) { - debug!("split_to_width: considering slice (offset={}, range={}, \ - remain_width={})", + debug!("split_to_inline_size: considering slice (offset={}, range={}, \ + remain_inline_size={})", offset, slice_range, - remaining_width); + remaining_inline_size); let metrics = text_fragment_info.run.metrics_for_slice(glyphs, &slice_range); let advance = metrics.advance_width; let should_continue; - if advance <= remaining_width { + if advance <= remaining_inline_size { should_continue = true; if starts_line && pieces_processed_count == 0 && glyphs.is_whitespace() { - debug!("split_to_width: case=skipping leading trimmable whitespace"); - left_range.shift_by(slice_range.length()); + debug!("split_to_inline_size: case=skipping leading trimmable whitespace"); + inline_start_range.shift_by(slice_range.length()); } else { - debug!("split_to_width: case=enlarging span"); - remaining_width = remaining_width - advance; - left_range.extend_by(slice_range.length()); + debug!("split_to_inline_size: case=enlarging span"); + remaining_inline_size = remaining_inline_size - advance; + inline_start_range.extend_by(slice_range.length()); } } else { - // The advance is more than the remaining width. + // The advance is more than the remaining inline-size. should_continue = false; let slice_begin = offset + slice_range.begin(); let slice_end = offset + slice_range.end(); if glyphs.is_whitespace() { // If there are still things after the trimmable whitespace, create the - // right chunk. + // inline-end chunk. if slice_end < text_fragment_info.range.end() { - debug!("split_to_width: case=skipping trimmable trailing \ + debug!("split_to_inline_size: case=skipping trimmable trailing \ whitespace, then split remainder"); - let right_range_end = text_fragment_info.range.end() - slice_end; - right_range = Some(Range::new(slice_end, right_range_end)); + let inline_end_range_end = text_fragment_info.range.end() - slice_end; + inline_end_range = Some(Range::new(slice_end, inline_end_range_end)); } else { - debug!("split_to_width: case=skipping trimmable trailing \ + debug!("split_to_inline_size: case=skipping trimmable trailing \ whitespace"); } } else if slice_begin < text_fragment_info.range.end() { - // There are still some things left over at the end of the line. Create - // the right chunk. - let right_range_end = text_fragment_info.range.end() - slice_begin; - right_range = Some(Range::new(slice_begin, right_range_end)); - debug!("split_to_width: case=splitting remainder with right range={:?}", - right_range); + // There are still some things inline-start over at the end of the line. Create + // the inline-end chunk. + let inline_end_range_end = text_fragment_info.range.end() - slice_begin; + inline_end_range = Some(Range::new(slice_begin, inline_end_range_end)); + debug!("split_to_inline_size: case=splitting remainder with inline_end range={:?}", + inline_end_range); } } @@ -1225,19 +1243,19 @@ impl Fragment { } } - let left_is_some = left_range.length() > CharIndex(0); + let inline_start_is_some = inline_start_range.length() > CharIndex(0); - if (pieces_processed_count == 1 || !left_is_some) && !starts_line { + if (pieces_processed_count == 1 || !inline_start_is_some) && !starts_line { None } else { - let left = if left_is_some { - Some(SplitInfo::new(left_range, text_fragment_info)) + let inline_start = if inline_start_is_some { + Some(SplitInfo::new(inline_start_range, text_fragment_info)) } else { None }; - let right = right_range.map(|right_range| SplitInfo::new(right_range, text_fragment_info)); + let inline_end = inline_end_range.map(|inline_end_range| SplitInfo::new(inline_end_range, text_fragment_info)); - Some((left, right, text_fragment_info.run.clone())) + Some((inline_start, inline_end, text_fragment_info.run.clone())) } } } @@ -1251,121 +1269,121 @@ impl Fragment { } } - /// Assigns replaced width, padding, and margins for this fragment only if it is replaced + /// Assigns replaced inline-size, padding, and margins for this fragment only if it is replaced /// content per CSS 2.1 § 10.3.2. - pub fn assign_replaced_width_if_necessary(&mut self, - container_width: Au, + pub fn assign_replaced_inline_size_if_necessary(&mut self, + container_inline_size: Au, inline_fragment_context: Option) { match self.specific { GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | TableRowFragment | TableWrapperFragment => return, - TableColumnFragment(_) => fail!("Table column fragments do not have width"), + TableColumnFragment(_) => fail!("Table column fragments do not have inline_size"), UnscannedTextFragment(_) => fail!("Unscanned text fragments should have been scanned by now!"), ImageFragment(_) | ScannedTextFragment(_) => {} }; - self.compute_border_padding_margins(container_width, inline_fragment_context); + self.compute_border_padding_margins(container_inline_size, inline_fragment_context); - let style_width = self.style().get_box().width; - let style_height = self.style().get_box().height; - let noncontent_width = self.border_padding.horizontal(); + let style_inline_size = self.style().content_inline_size(); + let style_block_size = self.style().content_block_size(); + let noncontent_inline_size = self.border_padding.inline_start_end(); match self.specific { ScannedTextFragment(_) => { - // Scanned text fragments will have already had their content widths assigned by this + // Scanned text fragments will have already had their content inline-sizes assigned by this // point. - self.border_box.size.width = self.border_box.size.width + noncontent_width + self.border_box.size.inline = self.border_box.size.inline + noncontent_inline_size } ImageFragment(ref mut image_fragment_info) => { // TODO(ksh8281): compute border,margin - let width = ImageFragmentInfo::style_length(style_width, - image_fragment_info.dom_width, - container_width); - let height = ImageFragmentInfo::style_length(style_height, - image_fragment_info.dom_height, + let inline_size = ImageFragmentInfo::style_length(style_inline_size, + image_fragment_info.dom_inline_size, + container_inline_size); + let block_size = ImageFragmentInfo::style_length(style_block_size, + image_fragment_info.dom_block_size, Au(0)); - let width = match (width,height) { - (Auto, Auto) => image_fragment_info.image_width(), + let inline_size = match (inline_size,block_size) { + (Auto, Auto) => image_fragment_info.image_inline_size(), (Auto,Specified(h)) => { let scale = image_fragment_info. - image_height().to_f32().unwrap() / h.to_f32().unwrap(); - Au::new((image_fragment_info.image_width().to_f32().unwrap() / scale) as i32) + image_block_size().to_f32().unwrap() / h.to_f32().unwrap(); + Au::new((image_fragment_info.image_inline_size().to_f32().unwrap() / scale) as i32) }, (Specified(w), _) => w, }; - self.border_box.size.width = width + noncontent_width; - image_fragment_info.computed_width = Some(width); + self.border_box.size.inline = inline_size + noncontent_inline_size; + image_fragment_info.computed_inline_size = Some(inline_size); } _ => fail!("this case should have been handled above"), } } - /// Assign height for this fragment if it is replaced content. The width must have been assigned + /// Assign block-size for this fragment if it is replaced content. The inline-size must have been assigned /// first. /// /// Ideally, this should follow CSS 2.1 § 10.6.2. - pub fn assign_replaced_height_if_necessary(&mut self) { + pub fn assign_replaced_block_size_if_necessary(&mut self) { match self.specific { GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | TableRowFragment | TableWrapperFragment => return, - TableColumnFragment(_) => fail!("Table column fragments do not have height"), + TableColumnFragment(_) => fail!("Table column fragments do not have block_size"), UnscannedTextFragment(_) => fail!("Unscanned text fragments should have been scanned by now!"), ImageFragment(_) | ScannedTextFragment(_) => {} } - let style_width = self.style().get_box().width; - let style_height = self.style().get_box().height; - let noncontent_height = self.border_padding.vertical(); + let style_inline_size = self.style().content_inline_size(); + let style_block_size = self.style().content_block_size(); + let noncontent_block_size = self.border_padding.block_start_end(); match self.specific { ImageFragment(ref mut image_fragment_info) => { // TODO(ksh8281): compute border,margin,padding - let width = image_fragment_info.computed_width(); - // FIXME(ksh8281): we shouldn't assign height this way - // we don't know about size of parent's height - let height = ImageFragmentInfo::style_length(style_height, - image_fragment_info.dom_height, + let inline_size = image_fragment_info.computed_inline_size(); + // FIXME(ksh8281): we shouldn't assign block-size this way + // we don't know about size of parent's block-size + let block_size = ImageFragmentInfo::style_length(style_block_size, + image_fragment_info.dom_block_size, Au(0)); - let height = match (style_width, image_fragment_info.dom_width, height) { + let block_size = match (style_inline_size, image_fragment_info.dom_inline_size, block_size) { (LPA_Auto, None, Auto) => { - image_fragment_info.image_height() + image_fragment_info.image_block_size() }, (_,_,Auto) => { - let scale = image_fragment_info.image_width().to_f32().unwrap() - / width.to_f32().unwrap(); - Au::new((image_fragment_info.image_height().to_f32().unwrap() / scale) as i32) + let scale = image_fragment_info.image_inline_size().to_f32().unwrap() + / inline_size.to_f32().unwrap(); + Au::new((image_fragment_info.image_block_size().to_f32().unwrap() / scale) as i32) }, (_,_,Specified(h)) => { h } }; - image_fragment_info.computed_height = Some(height); - self.border_box.size.height = height + noncontent_height + image_fragment_info.computed_block_size = Some(block_size); + self.border_box.size.block = block_size + noncontent_block_size } ScannedTextFragment(_) => { - // Scanned text fragments' content heights are calculated by the text run scanner + // Scanned text fragments' content block-sizes are calculated by the text run scanner // during flow construction. - self.border_box.size.height = self.border_box.size.height + noncontent_height + self.border_box.size.block = self.border_box.size.block + noncontent_block_size } _ => fail!("should have been handled above"), } } - /// Calculates height above baseline, depth below baseline, and ascent for this fragment when + /// Calculates block-size above baseline, depth below baseline, and ascent for this fragment when /// used in an inline formatting context. See CSS 2.1 § 10.8.1. pub fn inline_metrics(&self) -> InlineMetrics { match self.specific { ImageFragment(ref image_fragment_info) => { - let computed_height = image_fragment_info.computed_height(); + let computed_block_size = image_fragment_info.computed_block_size(); InlineMetrics { - height_above_baseline: computed_height + self.border_padding.vertical(), + block_size_above_baseline: computed_block_size + self.border_padding.block_start_end(), depth_below_baseline: Au(0), - ascent: computed_height + self.border_padding.bottom, + ascent: computed_block_size + self.border_padding.block_end, } } ScannedTextFragment(ref text_fragment) => { @@ -1376,9 +1394,9 @@ impl Fragment { } _ => { InlineMetrics { - height_above_baseline: self.border_box.size.height, + block_size_above_baseline: self.border_box.size.block, depth_below_baseline: Au(0), - ascent: self.border_box.size.height, + ascent: self.border_box.size.block, } } } @@ -1395,37 +1413,26 @@ impl Fragment { } } - /// A helper function to return a debug string describing the side offsets for one of the rect - /// box model properties (border, padding, or margin). - fn side_offsets_debug_fmt(&self, name: &str, - value: SideOffsets2D, - f: &mut fmt::Formatter) -> fmt::Result { - if value.is_zero() { - Ok(()) - } else { - write!(f, "{}{},{},{},{}", - name, - value.top, - value.right, - value.bottom, - value.left) - } - } - /// Sends the size and position of this iframe fragment to the constellation. This is out of /// line to guide inlining. #[inline(never)] fn finalize_position_and_size_of_iframe(&self, iframe_fragment: &IframeFragmentInfo, - offset: Point2D, + offset: LogicalPoint, layout_context: &LayoutContext) { - let left = offset.x + self.margin.left + self.border_padding.left; - let top = offset.y + self.margin.top + self.border_padding.top; - let width = self.content_box().size.width; - let height = self.content_box().size.height; - let origin = Point2D(geometry::to_frac_px(left) as f32, geometry::to_frac_px(top) as f32); - let size = Size2D(geometry::to_frac_px(width) as f32, geometry::to_frac_px(height) as f32); - let rect = Rect(origin, size); + let inline_start = offset.i + self.margin.inline_start + self.border_padding.inline_start; + let block_start = offset.b + self.margin.block_start + self.border_padding.block_start; + let inline_size = self.content_box().size.inline; + let block_size = self.content_box().size.block; + // FIXME(#2795): Get the real container size + let container_size = Size2D::zero(); + let rect = LogicalRect::new( + self.style.writing_mode, + geometry::to_frac_px(inline_start) as f32, + geometry::to_frac_px(block_start) as f32, + geometry::to_frac_px(inline_size) as f32, + geometry::to_frac_px(block_size) as f32 + ).to_physical(self.style.writing_mode, container_size); debug!("finalizing position and size of iframe for {:?},{:?}", iframe_fragment.pipeline_id, @@ -1452,9 +1459,9 @@ impl fmt::Show for Fragment { TableWrapperFragment => "TableWrapperFragment", UnscannedTextFragment(_) => "UnscannedTextFragment", })); - try!(self.side_offsets_debug_fmt("bp", self.border_padding, f)); + try!(write!(f, "bp {}", self.border_padding)); try!(write!(f, " ")); - try!(self.side_offsets_debug_fmt("m", self.margin, f)); + try!(write!(f, "m {}", self.margin)); write!(f, ")") } } diff --git a/src/components/layout/incremental.rs b/src/components/layout/incremental.rs index 710e3979e0b..d04c068b6aa 100644 --- a/src/components/layout/incremental.rs +++ b/src/components/layout/incremental.rs @@ -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, diff --git a/src/components/layout/inline.rs b/src/components/layout/inline.rs index f2bddecffed..be44969eb5a 100644 --- a/src/components/layout/inline.rs +++ b/src/components/layout/inline.rs @@ -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 ->+ - - - - - - - - +---------+---- | /// | | | | ^ | - /// | | | | size.height | + /// | | | | size.block-size | /// | I like truffles, | | v | /// | + - - - - - - - - +---------+---- | /// | | | | - /// | |<------ size.width ------->| | + /// | |<------ size.inline-size ------->| | /// | | /// | | /// +-----------------------------------------------------------+ /// ~~~ - pub bounds: Rect, + pub bounds: LogicalRect, /// 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 + pub green_zone: LogicalSize } int_range_index! { @@ -263,22 +264,22 @@ struct LineBreaker { pub work_list: RingBuf, pub pending_line: Line, pub lines: Vec, - 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) { + -> (LogicalRect, 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, - /// 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 { - model::border_from_style(&*self.style) + #[inline] + pub fn border(&self) -> LogicalMargin { + self.style.logical_border_width() } /// Returns the dimensions of the padding in this fragment range. - pub fn padding(&self) -> SideOffsets2D { + #[inline] + pub fn padding(&self) -> LogicalMargin { // 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, } diff --git a/src/components/layout/layout_task.rs b/src/components/layout/layout_task.rs index 46708e36c90..06b513f79af 100644 --- a/src/components/layout/layout_task.rs +++ b/src/components/layout/layout_task.rs @@ -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 { diff --git a/src/components/layout/model.rs b/src/components/layout/model.rs index dc147b77c8b..65f0c3704e3 100644 --- a/src/components/layout/model.rs +++ b/src/components/layout/model.rs @@ -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 { - 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 { +pub fn padding_from_style(style: &ComputedValues, containing_block_inline_size: Au) + -> LogicalMargin { 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))) } diff --git a/src/components/layout/parallel.rs b/src/components/layout/parallel.rs index 458360f9228..ebf4a560c01 100644 --- a/src/components/layout/parallel.rs +++ b/src/components/layout/parallel.rs @@ -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), }) }); diff --git a/src/components/layout/table.rs b/src/components/layout/table.rs index e9ac3cb412c..4f66564d995 100644 --- a/src/components/layout/table.rs +++ b/src/components/layout/table.rs @@ -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, + /// Column inline-sizes + pub col_inline_sizes: Vec, - /// Column min widths. - pub col_min_widths: Vec, + /// Column min inline-sizes. + pub col_min_inline_sizes: Vec, - /// Column pref widths. - pub col_pref_widths: Vec, + /// Column pref inline-sizes. + pub col_pref_inline_sizes: Vec, /// 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, kid_widths: &Vec) -> 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, kid_inline_sizes: &Vec) -> 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 { - &mut self.col_widths + fn col_inline_sizes<'a>(&'a mut self) -> &'a mut Vec { + &mut self.col_inline_sizes } - fn col_min_widths<'a>(&'a self) -> &'a Vec { - &self.col_min_widths + fn col_min_inline_sizes<'a>(&'a self) -> &'a Vec { + &self.col_min_inline_sizes } - fn col_pref_widths<'a>(&'a self) -> &'a Vec { - &self.col_pref_widths + fn col_pref_inline_sizes<'a>(&'a self) -> &'a Vec { + &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)) } } diff --git a/src/components/layout/table_caption.rs b/src/components/layout/table_caption.rs index 63fbf672681..9ad0e017813 100644 --- a/src/components/layout/table_caption.rs +++ b/src/components/layout/table_caption.rs @@ -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) { diff --git a/src/components/layout/table_cell.rs b/src/components/layout/table_cell.rs index 1538bab5df5..57bc806f7fc 100644 --- a/src/components/layout/table_cell.rs +++ b/src/components/layout/table_cell.rs @@ -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) { diff --git a/src/components/layout/table_colgroup.rs b/src/components/layout/table_colgroup.rs index 212629303c9..a27cff86deb 100644 --- a/src/components/layout/table_colgroup.rs +++ b/src/components/layout/table_colgroup.rs @@ -26,8 +26,8 @@ pub struct TableColGroupFlow { /// The table column fragments pub cols: Vec, - /// The specified widths of table columns - pub widths: Vec, + /// The specified inline-sizes of table columns + pub inline_sizes: Vec, } 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) { } } diff --git a/src/components/layout/table_row.rs b/src/components/layout/table_row.rs index d4935c1c0ed..6e8f5bfcfd7 100644 --- a/src/components/layout/table_row.rs +++ b/src/components/layout/table_row.rs @@ -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, + /// Column inline-sizes. + pub col_inline_sizes: Vec, - /// Column min widths. - pub col_min_widths: Vec, + /// Column min inline-sizes. + pub col_min_inline_sizes: Vec, - /// Column pref widths. - pub col_pref_widths: Vec, + /// Column pref inline-sizes. + pub col_pref_inline_sizes: Vec, } 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 { - &mut self.col_widths + fn col_inline_sizes<'a>(&'a mut self) -> &'a mut Vec { + &mut self.col_inline_sizes } - fn col_min_widths<'a>(&'a self) -> &'a Vec { - &self.col_min_widths + fn col_min_inline_sizes<'a>(&'a self) -> &'a Vec { + &self.col_min_inline_sizes } - fn col_pref_widths<'a>(&'a self) -> &'a Vec { - &self.col_pref_widths + fn col_pref_inline_sizes<'a>(&'a self) -> &'a Vec { + &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) { diff --git a/src/components/layout/table_rowgroup.rs b/src/components/layout/table_rowgroup.rs index e36f58bf482..0cfd3f080a7 100644 --- a/src/components/layout/table_rowgroup.rs +++ b/src/components/layout/table_rowgroup.rs @@ -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, + /// Column inline-sizes + pub col_inline_sizes: Vec, - /// Column min widths. - pub col_min_widths: Vec, + /// Column min inline-sizes. + pub col_min_inline_sizes: Vec, - /// Column pref widths. - pub col_pref_widths: Vec, + /// Column pref inline-sizes. + pub col_pref_inline_sizes: Vec, } 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 { - &mut self.col_widths + fn col_inline_sizes<'a>(&'a mut self) -> &'a mut Vec { + &mut self.col_inline_sizes } - fn col_min_widths<'a>(&'a self) -> &'a Vec { - &self.col_min_widths + fn col_min_inline_sizes<'a>(&'a self) -> &'a Vec { + &self.col_min_inline_sizes } - fn col_pref_widths<'a>(&'a self) -> &'a Vec { - &self.col_pref_widths + fn col_pref_inline_sizes<'a>(&'a self) -> &'a Vec { + &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) { diff --git a/src/components/layout/table_wrapper.rs b/src/components/layout/table_wrapper.rs index 7c04847faf1..5d431e18c4e 100644 --- a/src/components/layout/table_wrapper.rs +++ b/src/components/layout/table_wrapper.rs @@ -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, + /// Column inline-sizes + pub col_inline_sizes: Vec, /// 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) } } diff --git a/src/components/layout/text.rs b/src/components/layout/text.rs index 5991df7db44..c6fa2bdf742 100644 --- a/src/components/layout/text.rs +++ b/src/components/layout/text.rs @@ -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 { diff --git a/src/components/main/servo.rs b/src/components/main/servo.rs index aa61286bd32..7bd2a3e4cfa 100644 --- a/src/components/main/servo.rs +++ b/src/components/main/servo.rs @@ -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(); diff --git a/src/components/style/properties/mod.rs.mako b/src/components/style/properties/mod.rs.mako index 55ec83cc038..e6506c4472d 100644 --- a/src/components/style/properties/mod.rs.mako +++ b/src/components/style/properties/mod.rs.mako @@ -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 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 { - <%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 { one_component_value(input).and_then(|c| from_component_value(c, base_url)) @@ -149,8 +154,8 @@ pub mod longhands { - <%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 { - <%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; @@ -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>(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, % 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 { + 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 { + 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 { + 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 { + // 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 { @@ -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(); diff --git a/src/components/style/style.rs b/src/components/style/style.rs index 31fd84dccd9..dc70e6e9d5f 100644 --- a/src/components/style/style.rs +++ b/src/components/style/style.rs @@ -17,6 +17,7 @@ extern crate debug; extern crate collections; +extern crate geom; extern crate num; extern crate serialize; extern crate sync; diff --git a/src/components/util/geometry.rs b/src/components/util/geometry.rs index e0e980c7659..70882f17178 100644 --- a/src/components/util/geometry.rs +++ b/src/components/util/geometry.rs @@ -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 { diff --git a/src/components/util/logical_geometry.rs b/src/components/util/logical_geometry.rs index bd0ea74fed4..293c938c77f 100644 --- a/src/components/util/logical_geometry.rs +++ b/src/components/util/logical_geometry.rs @@ -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 { - 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 Show for LogicalSize { 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 LogicalSize { #[inline] pub fn zero(mode: WritingMode) -> LogicalSize { 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 LogicalSize { #[inline] - pub fn new(mode: WritingMode, isize: T, bsize: T) -> LogicalSize { + pub fn new(mode: WritingMode, inline: T, block: T) -> LogicalSize { LogicalSize { - isize: isize, - bsize: bsize, + inline: inline, + block: block, debug_writing_mode: DebugWritingMode::new(mode), } } @@ -182,9 +183,9 @@ impl LogicalSize { 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 LogicalSize { 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 LogicalSize { 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 LogicalSize { 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 LogicalSize { pub fn to_physical(&self, mode: WritingMode) -> Size2D { 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> Add, LogicalSize> for LogicalSize { 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> Sub, LogicalSize> for LogicalSize { 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> LogicalPoint { } } +impl> LogicalPoint { + /// This doesn’t really makes sense, + /// but happens when dealing with mutliple origins. + #[inline] + pub fn add_point(&self, other: &LogicalPoint) -> LogicalPoint { + 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> Add, LogicalPoint> for LogicalPoint { #[inline] fn add(&self, other: &LogicalSize) -> LogicalPoint { 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> Sub, LogicalPoint> for LogicalPoint { 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> Sub, LogicalPoint> for LogicalPoint { /// A positive "margin" can be added to a rectangle to obtain a bigger rectangle. #[deriving(PartialEq, Eq, Clone)] pub struct LogicalMargin { - 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 Show for LogicalMargin { 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 LogicalMargin { #[inline] pub fn zero(mode: WritingMode) -> LogicalMargin { 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 LogicalMargin { #[inline] - pub fn new(mode: WritingMode, bstart: T, iend: T, bend: T, istart: T) -> LogicalMargin { + pub fn new(mode: WritingMode, block_start: T, inline_end: T, block_end: T, inline_start: T) + -> LogicalMargin { 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 { + LogicalMargin::new(mode, value, value, value, value) + } + #[inline] pub fn from_physical(mode: WritingMode, offsets: SideOffsets2D) -> LogicalMargin { - 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 LogicalMargin { 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 LogicalMargin { 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 LogicalMargin { 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 LogicalMargin { 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 LogicalMargin { 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 LogicalMargin { 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 LogicalMargin { 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 LogicalMargin { 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 LogicalMargin { impl> LogicalMargin { #[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> LogicalMargin { 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> Add, LogicalMargin> for LogicalMargin 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> Sub, LogicalMargin> for LogicalMargin 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 { impl Show for LogicalRect { 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 LogicalRect { impl LogicalRect { #[inline] - pub fn new(mode: WritingMode, istart: T, bstart: T, isize: T, bsize: T) -> LogicalRect { + pub fn new(mode: WritingMode, inline_start: T, block_start: T, inline: T, block: T) + -> LogicalRect { 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, size: LogicalSize) + -> LogicalRect { + 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 + Sub> LogicalRect { #[inline] pub fn from_physical(mode: WritingMode, rect: Rect, container_size: Size2D) -> LogicalRect { - 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 + Sub> LogicalRect { 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 + Sub> LogicalRect { mode_to, self.to_physical(mode_from, container_size), container_size) } } + + pub fn translate(&self, offset: &LogicalPoint) -> LogicalRect { + 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 + Sub> LogicalRect { + #[inline] + pub fn union(&self, other: &LogicalRect) -> LogicalRect { + 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 + Sub> Add, LogicalRect> for LogicalRect { @@ -844,13 +918,13 @@ impl + Sub> Add, LogicalRect> 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 + Sub> Sub, LogicalRect> 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, diff --git a/src/components/util/opts.rs b/src/components/util/opts.rs index bdd1d2d4347..abf460bb46d 100644 --- a/src/components/util/opts.rs +++ b/src/components/util/opts.rs @@ -49,6 +49,9 @@ pub struct Opts { /// and cause it to produce output on that interval (`-m`). pub memory_profiler_period: Option, + /// 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 { 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 { 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 + } +} diff --git a/src/test/harness/reftest/reftest.rs b/src/test/harness/reftest/reftest.rs index 7e6638a37d9..eea2d9a5c22 100644 --- a/src/test/harness/reftest/reftest.rs +++ b/src/test/harness/reftest/reftest.rs @@ -82,8 +82,8 @@ fn parse_lists(file: &String, servo_args: &[String]) -> Vec { }; 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; } diff --git a/src/test/ref/basic.list b/src/test/ref/basic.list index 65982c1faa9..b6e85d9a646 100644 --- a/src/test/ref/basic.list +++ b/src/test/ref/basic.list @@ -75,7 +75,10 @@ == pseudo_element_a.html pseudo_element_b.html == linebreak_simple_a.html linebreak_simple_b.html == linebreak_inline_span_a.html linebreak_inline_span_b.html -== overconstrained_block.html overconstrained_block_ref.html + +# Should be == with expected failure. See #2797 +!= overconstrained_block.html overconstrained_block_ref.html + == overflow_auto.html overflow_simple_b.html == overflow_scroll.html overflow_simple_b.html == overflow_simple_a.html overflow_simple_b.html