layout: Take min-height and max-height into account

This commit is contained in:
Patrick Walton 2014-03-28 12:58:16 -07:00
parent cd9d824c21
commit 9874d0f9d3

View file

@ -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;