diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2014-03-28 12:58:16 -0700 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2014-04-03 14:50:56 -0700 |
commit | 9874d0f9d307482b87949e58e05cb85e19955183 (patch) | |
tree | 6c5b7000e623bad26b44546082940690ee4bb985 /src | |
parent | cd9d824c21167721fca40a4eff9563b8316d6c1a (diff) | |
download | servo-9874d0f9d307482b87949e58e05cb85e19955183.tar.gz servo-9874d0f9d307482b87949e58e05cb85e19955183.zip |
layout: Take `min-height` and `max-height` into account
Diffstat (limited to 'src')
-rw-r--r-- | src/components/main/layout/block.rs | 183 |
1 files changed, 156 insertions, 27 deletions
diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs index 6622af8daa3..168ae570c04 100644 --- a/src/components/main/layout/block.rs +++ b/src/components/main/layout/block.rs @@ -12,24 +12,33 @@ //! //! CB: Containing Block of the current flow. -use layout::box_::{Box, ImageBox, ScannedTextBox}; +use layout::box_::{Box, ImageBox, MainBoxKind, ScannedTextBox}; use layout::construct::FlowConstructor; use layout::context::LayoutContext; -use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData}; -use layout::floats::{FloatKind, Floats, PlacementInfo}; +use layout::display_list_builder::{DisplayListBuilder, DisplayListBuildingInfo}; +use layout::floats::{ClearBoth, ClearLeft, ClearRight, FloatKind, Floats, PlacementInfo}; use layout::flow::{BaseFlow, BlockFlowClass, FlowClass, Flow, ImmutableFlowUtils}; -use layout::flow::{mut_base, PreorderFlowTraversal, PostorderFlowTraversal, MutableFlowUtils}; +use layout::flow::{MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal, mut_base}; use layout::flow; -use layout::model::{MaybeAuto, Specified, Auto, specified_or_none, specified}; +use layout::model::{Auto, IntrinsicWidths, MarginCollapseInfo, MarginsCollapse}; +use layout::model::{MarginsCollapseThrough, MaybeAuto, NoCollapsibleMargins, Specified, specified}; +use layout::model::{specified_or_none}; use layout::wrapper::ThreadSafeLayoutNode; -use style::computed_values::{position}; +use style::ComputedValues; +use style::computed_values::{clear, position}; -use std::cell::RefCell; use geom::{Point2D, Rect, Size2D}; -use gfx::display_list::{DisplayListCollection, DisplayList}; +use gfx::color; +use gfx::display_list::{BackgroundAndBorderLevel, BlockLevel, RootOfStackingContextLevel}; +use gfx::display_list::{StackingContext}; +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::smallvec::{SmallVec, SmallVec0}; +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 sync::Arc; /// Information specific to floated blocks. pub struct FloatedBlockInfo { @@ -98,7 +107,7 @@ impl HeightConstraintSolution { content_height: Au, available_height: Au, static_y_offset: Au) - -> HeightConstraintSolution { + -> 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 // first box of the element. @@ -265,6 +274,115 @@ impl HeightConstraintSolution { } } +/// 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 +/// current calculated value of `height`. +/// +/// See CSS 2.1 § 10.7. +struct CandidateHeightIterator { + height: MaybeAuto, + max_height: Option<Au>, + min_height: Au, + candidate_value: Au, + status: CandidateHeightIteratorStatus, +} + +impl CandidateHeightIterator { + pub fn new(style: &ComputedValues, auto_value: Au, is_absolutely_positioned: bool) + -> CandidateHeightIterator { + // Per CSS 2.1 § 10.7, if the height is not *specified explicitly*, then we ignore + // `min-height` and `max-height`. Heights are considered to be specified explicitly if the + // element is absolutely positioned or the value of the containing block's height depends + // on the content. + // + // TODO(pcwalton): Consider heights specified explicitly if the containing block's height + // depends on the content. + let height_specified_explicitly = is_absolutely_positioned; + + let height = match style.Box.get().height { + LPA_Percentage(percent) if height_specified_explicitly => { + Specified(auto_value.scale_by(percent)) + } + LPA_Percentage(_) | LPA_Auto => Auto, + LPA_Length(length) => Specified(length), + }; + let max_height = match style.Box.get().max_height { + LPN_Percentage(percent) if height_specified_explicitly => { + Some(auto_value.scale_by(percent)) + } + LPN_Percentage(_) | LPN_None => None, + LPN_Length(length) => Some(length), + }; + let min_height = match style.Box.get().min_height { + LP_Percentage(percent) if height_specified_explicitly => auto_value.scale_by(percent), + LP_Percentage(_) => Au(0), + LP_Length(length) => length, + }; + + CandidateHeightIterator { + height: height, + max_height: max_height, + min_height: min_height, + candidate_value: Au(0), + status: InitialCandidateHeightStatus, + } + } + + 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 + } + _ if self.candidate_value < self.min_height => TryingMinCandidateHeightStatus, + _ => FoundCandidateHeightStatus, + } + } + TryingMaxCandidateHeightStatus => { + if self.candidate_value < self.min_height { + TryingMinCandidateHeightStatus + } else { + FoundCandidateHeightStatus + } + } + TryingMinCandidateHeightStatus | FoundCandidateHeightStatus => { + FoundCandidateHeightStatus + } + }; + + match self.status { + TryingHeightCandidateHeightStatus => Some((self.height, &mut self.candidate_value)), + TryingMaxCandidateHeightStatus => { + Some((Specified(self.max_height.unwrap()), &mut self.candidate_value)) + } + TryingMinCandidateHeightStatus => { + Some((Specified(self.min_height), &mut self.candidate_value)) + } + FoundCandidateHeightStatus => None, + InitialCandidateHeightStatus => fail!(), + } + } +} + +enum CandidateHeightIteratorStatus { + InitialCandidateHeightStatus, + TryingHeightCandidateHeightStatus, + TryingMaxCandidateHeightStatus, + TryingMinCandidateHeightStatus, + FoundCandidateHeightStatus, +} + +// A helper function used in height calculation. +fn translate_including_floats(cur_y: &mut Au, delta: Au, inorder: bool, floats: &mut Floats) { + *cur_y = *cur_y + delta; + + if inorder { + floats.translate(Point2D(Au(0), -delta)); + } +} + /// The real assign-heights traversal for flows with position 'absolute'. /// /// This is a traversal of an Absolute Flow tree. @@ -1288,25 +1406,36 @@ impl BlockFlow { // margin because of erroneous height calculation in Box_. // Check this when that has been fixed. let height_used_val = box_.border_box.get().size.height; - HeightConstraintSolution::solve_vertical_constraints_abs_replaced(height_used_val, - margin_top, - margin_bottom, - top, - bottom, - content_height, - available_height, - static_y_offset) + solution = Some(HeightConstraintSolution::solve_vertical_constraints_abs_replaced( + height_used_val, + margin_top, + margin_bottom, + top, + bottom, + content_height, + available_height, + static_y_offset)); } else { - HeightConstraintSolution::solve_vertical_constraints_abs_nonreplaced( - height_used_val, - margin_top, - margin_bottom, - top, - bottom, - content_height, - available_height, - static_y_offset) - }; + let mut candidate_height_iterator = + CandidateHeightIterator::new(style, containing_block_height, true); + + for (height_used_val, new_candidate_height) in candidate_height_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)); + + *new_candidate_height = solution.unwrap().height + } + } + + let solution = solution.unwrap(); let mut margin = box_.margin.get(); margin.top = solution.margin_top; |