mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 16:55:40 +00:00
servo: Merge #3556 - layout: Implement box-sizing: border-box
(from pcwalton:box-sizing); r=SimonSapin
Improves GitHub. Source-Repo: https://github.com/servo/servo Source-Revision: c7915028b498dc8426cdbb5b35f0ad270613a244
This commit is contained in:
parent
3a9cd8611d
commit
000f242577
@ -43,7 +43,7 @@ use std::cmp::{max, min};
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
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::{LPN_Percentage, LP_Length, LP_Percentage, box_sizing};
|
||||
use style::computed_values::{display, float, overflow};
|
||||
use sync::Arc;
|
||||
|
||||
@ -978,14 +978,30 @@ impl BlockFlow {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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);
|
||||
match self.fragment.style().get_box().box_sizing {
|
||||
box_sizing::content_box => {
|
||||
// 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);
|
||||
|
||||
// Take border and padding into account.
|
||||
let block_end_offset = self.fragment.border_padding.block_end;
|
||||
translate_including_floats(&mut cur_b, block_end_offset, &mut floats);
|
||||
}
|
||||
box_sizing::border_box => {
|
||||
// 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;
|
||||
translate_including_floats(&mut cur_b, delta, &mut floats);
|
||||
|
||||
// Take padding into account.
|
||||
let block_end_offset = self.fragment.border_padding.block_end -
|
||||
self.fragment.border_width().block_end;
|
||||
translate_including_floats(&mut cur_b, block_end_offset, &mut floats);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that `cur_b` is at the block-end of the border box, compute the final border box
|
||||
// position.
|
||||
@ -1203,10 +1219,17 @@ impl BlockFlow {
|
||||
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.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();
|
||||
|
||||
let block_size = match self.fragment.style().get_box().box_sizing {
|
||||
box_sizing::content_box => {
|
||||
solution.block_size + self.fragment.border_padding.block_start_end()
|
||||
}
|
||||
box_sizing::border_box => solution.block_size,
|
||||
};
|
||||
self.fragment.border_box.size.block = block_size;
|
||||
self.base.position.size.block = block_size;
|
||||
}
|
||||
|
||||
/// Add display items for Absolutely Positioned flow.
|
||||
@ -1919,28 +1942,35 @@ pub trait ISizeAndMarginsComputer {
|
||||
block.static_i_offset());
|
||||
}
|
||||
|
||||
/// Set the used values for inline-size and margins got from the relevant constraint equation.
|
||||
///
|
||||
/// Set the used values for inline-size and margins from the relevant constraint equation.
|
||||
/// This is called only once.
|
||||
///
|
||||
/// Set:
|
||||
/// + 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).
|
||||
/// * Used values for content inline-size, inline-start margin, and inline-end margin for this
|
||||
/// flow's box;
|
||||
/// * Inline-start coordinate of this flow's box;
|
||||
/// * Inline-start coordinate of the flow with respect to its containing block (if this is an
|
||||
/// absolute flow).
|
||||
fn set_inline_size_constraint_solutions(&self,
|
||||
block: &mut BlockFlow,
|
||||
solution: ISizeConstraintSolution) {
|
||||
block: &mut BlockFlow,
|
||||
solution: ISizeConstraintSolution) {
|
||||
let inline_size;
|
||||
{
|
||||
let fragment = block.fragment();
|
||||
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.start.i = fragment.margin.inline_start;
|
||||
// Border box inline-size.
|
||||
inline_size = solution.inline_size + fragment.border_padding.inline_start_end();
|
||||
|
||||
// The associated fragment has the border box of this flow.
|
||||
inline_size = match fragment.style().get_box().box_sizing {
|
||||
box_sizing::content_box => {
|
||||
solution.inline_size + fragment.border_padding.inline_start_end()
|
||||
}
|
||||
box_sizing::border_box => solution.inline_size,
|
||||
};
|
||||
|
||||
fragment.border_box.size.inline = inline_size;
|
||||
}
|
||||
|
||||
@ -1966,7 +1996,9 @@ pub trait ISizeAndMarginsComputer {
|
||||
ctx: &LayoutContext)
|
||||
-> MaybeAuto {
|
||||
MaybeAuto::from_style(block.fragment().style().content_inline_size(),
|
||||
self.containing_block_inline_size(block, parent_flow_inline_size, ctx))
|
||||
self.containing_block_inline_size(block,
|
||||
parent_flow_inline_size,
|
||||
ctx))
|
||||
}
|
||||
|
||||
fn containing_block_inline_size(&self,
|
||||
@ -1984,15 +2016,21 @@ pub trait ISizeAndMarginsComputer {
|
||||
block: &mut BlockFlow,
|
||||
ctx: &LayoutContext,
|
||||
parent_flow_inline_size: Au) {
|
||||
let mut input = self.compute_inline_size_constraint_inputs(block, parent_flow_inline_size, ctx);
|
||||
let mut input = self.compute_inline_size_constraint_inputs(block,
|
||||
parent_flow_inline_size,
|
||||
ctx);
|
||||
|
||||
let containing_block_inline_size = self.containing_block_inline_size(block, parent_flow_inline_size, ctx);
|
||||
let containing_block_inline_size = self.containing_block_inline_size(
|
||||
block,
|
||||
parent_flow_inline_size, ctx);
|
||||
|
||||
let mut solution = self.solve_inline_size_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) {
|
||||
// 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);
|
||||
@ -2000,8 +2038,9 @@ pub trait ISizeAndMarginsComputer {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// 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'.
|
||||
// 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 {
|
||||
@ -2018,16 +2057,18 @@ pub trait ISizeAndMarginsComputer {
|
||||
/// This is used by both replaced and non-replaced Blocks.
|
||||
///
|
||||
/// CSS 2.1 Section 10.3.3.
|
||||
/// Constraint Equation: margin-inline-start + margin-inline-end + inline-size = available_inline-size
|
||||
/// 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: &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 (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 inline-size is not 'auto', and inline-size + margins > available_inline-size, all
|
||||
// 'auto' margins are treated as 0.
|
||||
@ -2045,36 +2086,41 @@ pub trait ISizeAndMarginsComputer {
|
||||
}
|
||||
};
|
||||
|
||||
// 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 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)),
|
||||
// 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 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(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 exactly one value is 'auto', solve for it
|
||||
(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 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_inline_size, 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_inline_size, Au::new(0)),
|
||||
|
||||
// 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)
|
||||
}
|
||||
};
|
||||
// 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)
|
||||
}
|
||||
};
|
||||
ISizeConstraintSolution::new(inline_size, inline_start_margin, inline_end_margin)
|
||||
}
|
||||
}
|
||||
@ -2363,9 +2409,9 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
|
||||
impl ISizeAndMarginsComputer for BlockNonReplaced {
|
||||
/// Compute inline-start and inline-end margins and inline-size.
|
||||
fn solve_inline_size_constraints(&self,
|
||||
block: &mut BlockFlow,
|
||||
input: &ISizeConstraintInput)
|
||||
-> ISizeConstraintSolution {
|
||||
block: &mut BlockFlow,
|
||||
input: &ISizeConstraintInput)
|
||||
-> ISizeConstraintSolution {
|
||||
self.solve_block_inline_size_constraints(block, input)
|
||||
}
|
||||
}
|
||||
@ -2376,9 +2422,9 @@ impl ISizeAndMarginsComputer for BlockReplaced {
|
||||
/// ISize has already been calculated. We now calculate the margins just
|
||||
/// like for non-replaced blocks.
|
||||
fn solve_inline_size_constraints(&self,
|
||||
block: &mut BlockFlow,
|
||||
input: &ISizeConstraintInput)
|
||||
-> ISizeConstraintSolution {
|
||||
block: &mut BlockFlow,
|
||||
input: &ISizeConstraintInput)
|
||||
-> ISizeConstraintSolution {
|
||||
match input.computed_inline_size {
|
||||
Specified(_) => {},
|
||||
Auto => fail!("BlockReplaced: inline_size should have been computed by now")
|
||||
|
@ -592,11 +592,10 @@ impl Fragment {
|
||||
text::line_height_from_style(&*self.style, &font_metrics)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// Returns the sum of the inline-sizes of all the borders of this fragment. Note that this
|
||||
/// can be expensive to compute, so if possible use the `border_padding` field instead.
|
||||
#[inline]
|
||||
fn border_width(&self) -> LogicalMargin<Au> {
|
||||
pub fn border_width(&self) -> LogicalMargin<Au> {
|
||||
let style_border_width = match self.specific {
|
||||
ScannedTextFragment(_) => LogicalMargin::zero(self.style.writing_mode),
|
||||
_ => self.style().logical_border_width(),
|
||||
|
@ -1075,6 +1075,12 @@ pub mod longhands {
|
||||
// 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", experimental=True)}
|
||||
|
||||
// CSS Basic User Interface Module Level 3
|
||||
// http://dev.w3.org/csswg/css-ui/
|
||||
${switch_to_style_struct("Box")}
|
||||
|
||||
${single_keyword("box-sizing", "content-box border-box")}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user