mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
layout: Take min-height
and max-height
into account
This commit is contained in:
parent
cd9d824c21
commit
9874d0f9d3
1 changed files with 156 additions and 27 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue