aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-03-28 12:58:16 -0700
committerPatrick Walton <pcwalton@mimiga.net>2014-04-03 14:50:56 -0700
commit9874d0f9d307482b87949e58e05cb85e19955183 (patch)
tree6c5b7000e623bad26b44546082940690ee4bb985 /src
parentcd9d824c21167721fca40a4eff9563b8316d6c1a (diff)
downloadservo-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.rs183
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;