mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
layout: Implement box-sizing: border-box
.
Improves GitHub.
This commit is contained in:
parent
f7d2fb6ff8
commit
885fc1c28b
6 changed files with 139 additions and 70 deletions
|
@ -43,7 +43,7 @@ use std::cmp::{max, min};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use style::computed_values::{LPA_Auto, LPA_Length, LPA_Percentage, LPN_Length, LPN_None};
|
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 style::computed_values::{display, float, overflow};
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
|
|
||||||
|
@ -978,14 +978,30 @@ impl BlockFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
// Adjust `cur_b` as necessary to account for the explicitly-specified block-size.
|
||||||
block_size = candidate_block_size_iterator.candidate_value;
|
block_size = candidate_block_size_iterator.candidate_value;
|
||||||
let delta = block_size - (cur_b - block_start_offset);
|
let delta = block_size - (cur_b - block_start_offset);
|
||||||
translate_including_floats(&mut cur_b, delta, &mut floats);
|
translate_including_floats(&mut cur_b, delta, &mut floats);
|
||||||
|
|
||||||
// Compute content block-size and noncontent block-size.
|
// Take border and padding into account.
|
||||||
let block_end_offset = self.fragment.border_padding.block_end;
|
let block_end_offset = self.fragment.border_padding.block_end;
|
||||||
translate_including_floats(&mut cur_b, block_end_offset, &mut floats);
|
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
|
// Now that `cur_b` is at the block-end of the border box, compute the final border box
|
||||||
// position.
|
// position.
|
||||||
|
@ -1203,10 +1219,17 @@ impl BlockFlow {
|
||||||
self.fragment.margin.block_start = solution.margin_block_start;
|
self.fragment.margin.block_start = solution.margin_block_start;
|
||||||
self.fragment.margin.block_end = solution.margin_block_end;
|
self.fragment.margin.block_end = solution.margin_block_end;
|
||||||
self.fragment.border_box.start.b = Au(0);
|
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.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.
|
/// Add display items for Absolutely Positioned flow.
|
||||||
|
@ -1919,14 +1942,15 @@ pub trait ISizeAndMarginsComputer {
|
||||||
block.static_i_offset());
|
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.
|
/// This is called only once.
|
||||||
///
|
///
|
||||||
/// Set:
|
/// Set:
|
||||||
/// + used values for content inline-size, inline-start margin, and inline-end margin for this flow's box.
|
/// * Used values for content inline-size, inline-start margin, and inline-end margin for this
|
||||||
/// + x-coordinate of this flow's box.
|
/// flow's box;
|
||||||
/// + x-coordinate of the flow wrt its Containing Block (if this is an absolute flow).
|
/// * 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,
|
fn set_inline_size_constraint_solutions(&self,
|
||||||
block: &mut BlockFlow,
|
block: &mut BlockFlow,
|
||||||
solution: ISizeConstraintSolution) {
|
solution: ISizeConstraintSolution) {
|
||||||
|
@ -1936,11 +1960,17 @@ pub trait ISizeAndMarginsComputer {
|
||||||
fragment.margin.inline_start = solution.margin_inline_start;
|
fragment.margin.inline_start = solution.margin_inline_start;
|
||||||
fragment.margin.inline_end = solution.margin_inline_end;
|
fragment.margin.inline_end = solution.margin_inline_end;
|
||||||
|
|
||||||
// The associated fragment has the border box of this flow.
|
|
||||||
// Left border edge.
|
// Left border edge.
|
||||||
fragment.border_box.start.i = fragment.margin.inline_start;
|
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;
|
fragment.border_box.size.inline = inline_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1966,7 +1996,9 @@ pub trait ISizeAndMarginsComputer {
|
||||||
ctx: &LayoutContext)
|
ctx: &LayoutContext)
|
||||||
-> MaybeAuto {
|
-> MaybeAuto {
|
||||||
MaybeAuto::from_style(block.fragment().style().content_inline_size(),
|
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,
|
fn containing_block_inline_size(&self,
|
||||||
|
@ -1984,15 +2016,21 @@ pub trait ISizeAndMarginsComputer {
|
||||||
block: &mut BlockFlow,
|
block: &mut BlockFlow,
|
||||||
ctx: &LayoutContext,
|
ctx: &LayoutContext,
|
||||||
parent_flow_inline_size: Au) {
|
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);
|
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,
|
// If the tentative used inline-size is greater than 'max-inline-size', inline-size should
|
||||||
// but this time using the computed value of 'max-inline-size' as the computed value for 'inline-size'.
|
// be recalculated, but this time using the computed value of 'max-inline-size' as the
|
||||||
match specified_or_none(block.fragment().style().max_inline_size(), containing_block_inline_size) {
|
// 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 => {
|
Some(max_inline_size) if max_inline_size < solution.inline_size => {
|
||||||
input.computed_inline_size = Specified(max_inline_size);
|
input.computed_inline_size = Specified(max_inline_size);
|
||||||
solution = self.solve_inline_size_constraints(block, &input);
|
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,
|
// If the resulting inline-size is smaller than 'min-inline-size', inline-size should be
|
||||||
// but this time using the value of 'min-inline-size' as the computed value for 'inline-size'.
|
// 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(),
|
let computed_min_inline_size = specified(block.fragment().style().min_inline_size(),
|
||||||
containing_block_inline_size);
|
containing_block_inline_size);
|
||||||
if computed_min_inline_size > solution.inline_size {
|
if computed_min_inline_size > solution.inline_size {
|
||||||
|
@ -2018,13 +2057,15 @@ pub trait ISizeAndMarginsComputer {
|
||||||
/// This is used by both replaced and non-replaced Blocks.
|
/// This is used by both replaced and non-replaced Blocks.
|
||||||
///
|
///
|
||||||
/// CSS 2.1 Section 10.3.3.
|
/// 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)
|
/// where available_inline-size = CB inline-size - (horizontal border + padding)
|
||||||
fn solve_block_inline_size_constraints(&self,
|
fn solve_block_inline_size_constraints(&self,
|
||||||
_: &mut BlockFlow,
|
_: &mut BlockFlow,
|
||||||
input: &ISizeConstraintInput)
|
input: &ISizeConstraintInput)
|
||||||
-> ISizeConstraintSolution {
|
-> ISizeConstraintSolution {
|
||||||
let (computed_inline_size, inline_start_margin, inline_end_margin, available_inline_size) = (input.computed_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_start_margin,
|
||||||
input.inline_end_margin,
|
input.inline_end_margin,
|
||||||
input.available_inline_size);
|
input.available_inline_size);
|
||||||
|
@ -2045,20 +2086,25 @@ pub trait ISizeAndMarginsComputer {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Invariant: inline-start_margin + inline-size + inline-end_margin == available_inline-size
|
// Invariant: inline-start_margin + inline-size + inline-end_margin ==
|
||||||
let (inline_start_margin, inline_size, inline_end_margin) = match (inline_start_margin, computed_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
|
// If all have a computed value other than 'auto', the system is
|
||||||
// over-constrained so we discard the end margin.
|
// over-constrained so we discard the end margin.
|
||||||
(Specified(margin_start), Specified(inline_size), Specified(_margin_end)) =>
|
(Specified(margin_start), Specified(inline_size), Specified(_margin_end)) =>
|
||||||
(margin_start, inline_size, available_inline_size - (margin_start + inline_size)),
|
(margin_start, inline_size, available_inline_size -
|
||||||
|
(margin_start + inline_size)),
|
||||||
|
|
||||||
// If exactly one value is 'auto', solve for it
|
// If exactly one value is 'auto', solve for it
|
||||||
(Auto, Specified(inline_size), Specified(margin_end)) =>
|
(Auto, Specified(inline_size), Specified(margin_end)) =>
|
||||||
(available_inline_size - (inline_size + margin_end), inline_size, margin_end),
|
(available_inline_size - (inline_size + margin_end), inline_size, margin_end),
|
||||||
(Specified(margin_start), Auto, Specified(margin_end)) =>
|
(Specified(margin_start), Auto, Specified(margin_end)) =>
|
||||||
(margin_start, available_inline_size - (margin_start + margin_end), margin_end),
|
(margin_start, available_inline_size - (margin_start + margin_end),
|
||||||
|
margin_end),
|
||||||
(Specified(margin_start), Specified(inline_size), Auto) =>
|
(Specified(margin_start), Specified(inline_size), Auto) =>
|
||||||
(margin_start, inline_size, available_inline_size - (margin_start + inline_size)),
|
(margin_start, inline_size, available_inline_size -
|
||||||
|
(margin_start + inline_size)),
|
||||||
|
|
||||||
// If inline-size is set to 'auto', any other 'auto' value becomes '0',
|
// If inline-size is set to 'auto', any other 'auto' value becomes '0',
|
||||||
// and inline-size is solved for
|
// and inline-size is solved for
|
||||||
|
|
|
@ -592,11 +592,10 @@ impl Fragment {
|
||||||
text::line_height_from_style(&*self.style, &font_metrics)
|
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
|
/// Returns the sum of the inline-sizes of all the borders of this fragment. Note that this
|
||||||
/// it should only be called during intrinsic inline-size computation or computation of
|
/// can be expensive to compute, so if possible use the `border_padding` field instead.
|
||||||
/// `border_padding`. Other consumers of this information should simply consult that field.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn border_width(&self) -> LogicalMargin<Au> {
|
pub fn border_width(&self) -> LogicalMargin<Au> {
|
||||||
let style_border_width = match self.specific {
|
let style_border_width = match self.specific {
|
||||||
ScannedTextFragment(_) => LogicalMargin::zero(self.style.writing_mode),
|
ScannedTextFragment(_) => LogicalMargin::zero(self.style.writing_mode),
|
||||||
_ => self.style().logical_border_width(),
|
_ => self.style().logical_border_width(),
|
||||||
|
|
|
@ -1075,6 +1075,12 @@ pub mod longhands {
|
||||||
// FIXME(SimonSapin): Add 'mixed' and 'upright' (needs vertical text support)
|
// FIXME(SimonSapin): Add 'mixed' and 'upright' (needs vertical text support)
|
||||||
// FIXME(SimonSapin): initial (first) value should be 'mixed', when that's implemented
|
// FIXME(SimonSapin): initial (first) value should be 'mixed', when that's implemented
|
||||||
${single_keyword("text-orientation", "sideways sideways-left sideways-right", experimental=True)}
|
${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")}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -162,3 +162,4 @@ fragment=top != ../html/acid2.html acid2_ref.html
|
||||||
== vertical_align_text_top_a.html vertical_align_text_top_ref.html
|
== vertical_align_text_top_a.html vertical_align_text_top_ref.html
|
||||||
== vertical_align_text_bottom_a.html vertical_align_text_bottom_ref.html
|
== vertical_align_text_bottom_a.html vertical_align_text_bottom_ref.html
|
||||||
== inline_hypothetical_box_a.html inline_hypothetical_box_ref.html
|
== inline_hypothetical_box_a.html inline_hypothetical_box_ref.html
|
||||||
|
== box_sizing_border_box_a.html box_sizing_border_box_ref.html
|
||||||
|
|
8
tests/ref/box_sizing_border_box_a.html
Normal file
8
tests/ref/box_sizing_border_box_a.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<div style="width: 256px; height: 256px; background: purple; border: 8px solid blue; box-sizing: border-box;"></div>
|
||||||
|
<div style="width: 240px; height: 240px; background: purple; border: 8px solid blue;"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
9
tests/ref/box_sizing_border_box_ref.html
Normal file
9
tests/ref/box_sizing_border_box_ref.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<div style="width: 240px; height: 240px; background: purple; border: 8px solid blue;"></div>
|
||||||
|
<div style="width: 240px; height: 240px; background: purple; border: 8px solid blue;"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue