Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement CSS3 Calc #7496

Merged
merged 23 commits into from Sep 2, 2015
Merged
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9556141
Implement Calc for LengthOrPercentage
dzbarsky Aug 11, 2015
cb4d878
Implement Calc for LengthOrPercentageOrAuto
dzbarsky Aug 12, 2015
2bb6b45
Implement proper calc parsing
dzbarsky Aug 12, 2015
5df4b82
Implement font relative and viewport relative units for calc
dzbarsky Aug 12, 2015
af4d2e9
Clean up serialization and other hacks
dzbarsky Aug 13, 2015
64dc954
Clean up serialization code a little
dzbarsky Aug 13, 2015
cfa1e46
Clean up AST simplification code
dzbarsky Aug 13, 2015
6573e80
Properly serialize % values in calc expressions
dzbarsky Aug 13, 2015
663e0f6
Simplify like terms in all sum expressions, not just toplevel calc
dzbarsky Aug 13, 2015
63d0429
Simplify the calc AST simplification code
dzbarsky Aug 13, 2015
67db4fb
Remove stray changes
dzbarsky Aug 13, 2015
f8bd7c4
Fix some calc parsing panics
dzbarsky Aug 14, 2015
164af05
Expand out nested products
dzbarsky Aug 15, 2015
dcac654
Use the type system to enforce that product nodes are simplified away
dzbarsky Aug 15, 2015
53e8f7d
Get rid of some cloning
dzbarsky Aug 15, 2015
5ac205b
Clean up some stray lines
dzbarsky Aug 15, 2015
cdae523
Address review comments
dzbarsky Aug 23, 2015
25829bb
Add calc reftest
dzbarsky Aug 26, 2015
2591a89
Add calc parsing tests for the other properties
dzbarsky Aug 26, 2015
80d471d
Merge branch 'master' into calc
SimonSapin Sep 1, 2015
b30c4f7
Add support for the ch unit in calc()
SimonSapin Sep 1, 2015
9f48dcd
Fix font-size keywords parsing.
SimonSapin Sep 2, 2015
b51b7dd
Fix ch/em confusion.
SimonSapin Sep 2, 2015
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

Implement Calc for LengthOrPercentage

  • Loading branch information
dzbarsky committed Aug 26, 2015
commit 9556141e571757ccf261712a696ec65736b78a0b
@@ -331,9 +331,8 @@ impl CandidateBSizeIterator {
(LengthOrPercentageOrAuto::Length(length), _) => MaybeAuto::Specified(length),
};
let max_block_size = match (fragment.style.max_block_size(), block_container_block_size) {
(LengthOrPercentageOrNone::Percentage(percent), Some(block_container_block_size)) => {
Some(block_container_block_size.scale_by(percent))
}
(LengthOrPercentageOrNone::Percentage(percent), Some(block_container_block_size)) =>
Some(block_container_block_size.scale_by(percent)),
(LengthOrPercentageOrNone::Percentage(_), None) |
(LengthOrPercentageOrNone::None, _) => None,
(LengthOrPercentageOrNone::Length(length), _) => Some(length),
@@ -342,6 +341,10 @@ impl CandidateBSizeIterator {
(LengthOrPercentage::Percentage(percent), Some(block_container_block_size)) => {
block_container_block_size.scale_by(percent)
}
(LengthOrPercentage::Calc(calc), Some(block_container_block_size)) => {
calc.length() + block_container_block_size.scale_by(calc.percentage())
}
(LengthOrPercentage::Calc(calc), None) => calc.length(),
(LengthOrPercentage::Percentage(_), None) => Au(0),
(LengthOrPercentage::Length(length), _) => length,
};
@@ -1955,6 +1955,8 @@ fn position_to_offset(position: LengthOrPercentage, Au(total_length): Au) -> f32
fmin(1.0, (length as f32) / (total_length as f32))
}
LengthOrPercentage::Percentage(percentage) => percentage as f32,
LengthOrPercentage::Calc(calc) =>
fmin(1.0, calc.percentage() + (calc.length().0 as f32) / (total_length as f32)),
}
}

@@ -988,7 +988,12 @@ impl InlineFlow {
let percent_offset = line_height.scale_by(p);
offset_from_baseline = offset_from_baseline - percent_offset
}
}
vertical_align::T::Calc(calc) => {
let line_height = fragment.calculate_line_height(layout_context);
let percent_offset = line_height.scale_by(calc.percentage());
offset_from_baseline = offset_from_baseline - percent_offset - calc.length()
}
}
}
(offset_from_baseline - ascent, largest_size_updated)
}
@@ -416,7 +416,9 @@ pub fn specified_or_none(length: LengthOrPercentageOrNone, containing_length: Au
pub fn specified(length: LengthOrPercentage, containing_length: Au) -> Au {
match length {
LengthOrPercentage::Length(length) => length,
LengthOrPercentage::Percentage(p) => containing_length.scale_by(p)
LengthOrPercentage::Percentage(p) => containing_length.scale_by(p),
LengthOrPercentage::Calc(calc) =>
containing_length.scale_by(calc.percentage()) + calc.length(),
}
}

@@ -756,7 +756,7 @@ pub mod longhands {
pub mod computed_value {
use std::fmt;
use util::geometry::Au;
use values::CSSFloat;
use values::{CSSFloat, computed};
#[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone, HeapSizeOf)]
pub enum T {
@@ -765,6 +765,7 @@ pub mod longhands {
% endfor
Length(Au),
Percentage(CSSFloat),
Calc(computed::Calc),
}
impl fmt::Debug for T {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -774,6 +775,8 @@ pub mod longhands {
% endfor
&T::Length(length) => write!(f, "{:?}", length),
&T::Percentage(number) => write!(f, "{}%", number),
// XXX HACK WRONG
&T::Calc(calc) => write!(f, "{}%", 10.),
}
}
}
@@ -785,6 +788,7 @@ pub mod longhands {
% endfor
T::Length(value) => value.to_css(dest),
T::Percentage(percentage) => write!(dest, "{}%", percentage * 100.),
T::Calc(calc) => calc.to_css(dest),
}
}
}
@@ -805,12 +809,12 @@ pub mod longhands {
% endfor
SpecifiedValue::LengthOrPercentage(value) => {
match value.to_computed_value(context) {
computed::LengthOrPercentage::Length(value) => {
computed_value::T::Length(value)
}
computed::LengthOrPercentage::Percentage(value) => {
computed_value::T::Percentage(value)
}
computed::LengthOrPercentage::Length(value) =>
computed_value::T::Length(value),
computed::LengthOrPercentage::Percentage(value) =>
computed_value::T::Percentage(value),
computed::LengthOrPercentage::Calc(value) =>
computed_value::T::Calc(value),
}
}
}
@@ -1909,7 +1913,10 @@ pub mod longhands {
.map(|value| match value {
specified::LengthOrPercentage::Length(value) => value,
specified::LengthOrPercentage::Percentage(value) =>
specified::Length::FontRelative(specified::FontRelativeLength::Em(value))
specified::Length::FontRelative(specified::FontRelativeLength::Em(value)),
// XXX WRONG HACK
specified::LengthOrPercentage::Calc(calc) =>
specified::Length::FontRelative(specified::FontRelativeLength::Em(20.)),
})
.or_else(|()| {
match_ignore_ascii_case! { try!(input.expect_ident()),
@@ -353,11 +353,93 @@ pub mod specified {
}
}

#[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)]
pub struct Calc {
pub absolute: Option<Au>,
pub font_relative: Option<FontRelativeLength>,
pub viewport_percentage: Option<ViewportPercentageLength>,
pub percentage: Option<CSSFloat>,
}
impl Calc {
pub fn parse_component(&mut self, input: &mut Parser) -> Result<(), ()> {
match try!(input.next()) {
Token::Dimension(ref value, ref unit) => {
let value = value.value;
match_ignore_ascii_case! { unit,
"px" => self.absolute =
Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_PX) as i32)),
"in" => self.absolute =
Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_IN) as i32)),
"cm" => self.absolute =
Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_CM) as i32)),
"mm" => self.absolute =
Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_MM) as i32)),
"pt" => self.absolute =
Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_PT) as i32)),
"pc" => self.absolute =
Some(self.absolute.unwrap_or(Au(0)) + Au((value * AU_PER_PC) as i32))
// font-relative
/*"em" => Ok(Length::FontRelative(FontRelativeLength::Em(value))),
"ex" => Ok(Length::FontRelative(FontRelativeLength::Ex(value))),
"rem" => Ok(Length::FontRelative(FontRelativeLength::Rem(value))),
// viewport percentages
"vw" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vw(value))),
"vh" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vh(value))),
"vmin" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmin(value))),
"vmax" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmax(value)))*/
// Handle em, ex, rem, vw, vh, vmin, vmax
_ => return Err(())
}
},
Token::Percentage(ref value) =>
self.percentage = Some(self.percentage.unwrap_or(0.) + value.unit_value),
Token::Number(ref value) if value.value == 0. =>
self.absolute = self.absolute.or(Some(Au(0))),
_ => return Err(())
};
Ok(())
}

pub fn parse(input: &mut Parser) -> Result<Calc, ()> {
let mut calc = Calc {
absolute: None,
font_relative: None,
viewport_percentage: None,
percentage: None,
};

try!(calc.parse_component(input));
let operator = try!(input.next());
match operator {
Token::Delim('+') => (),
_ => return Err(())
};

try!(calc.parse_component(input));
Ok(calc)
}
}

impl ToCss for Calc {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
// XXX WRONG HACK
try!(write!(dest, "calc("));
if let Some(absolute) = self.absolute {
try!(write!(dest, "{}px", Au::to_px(absolute)));
}
if let Some(FontRelativeLength::Em(font_relative)) = self.font_relative {
try!(write!(dest, "{}em", font_relative));
}

write!(dest, ")")
}
}

#[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)]
pub enum LengthOrPercentage {
Length(Length),
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
Calc(Calc),
}

impl ToCss for LengthOrPercentage {
@@ -366,6 +448,7 @@ pub mod specified {
&LengthOrPercentage::Length(length) => length.to_css(dest),
&LengthOrPercentage::Percentage(percentage)
=> write!(dest, "{}%", percentage * 100.),
&LengthOrPercentage::Calc(calc) => calc.to_css(dest),
}
}
}
@@ -384,6 +467,10 @@ pub mod specified {
Ok(LengthOrPercentage::Percentage(value.unit_value)),
Token::Number(ref value) if value.value == 0. =>
Ok(LengthOrPercentage::Length(Length::Absolute(Au(0)))),
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
let calc = try!(input.parse_nested_block(Calc::parse));
Ok(LengthOrPercentage::Calc(calc))
},
_ => Err(())
}
}
@@ -938,10 +1025,50 @@ pub mod computed {
}
}

#[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)]
pub struct Calc {
length: Option<Au>,
percentage: Option<CSSFloat>,
}

impl Calc {
pub fn length(&self) -> Au {
self.length.unwrap_or(Au(0))
}

pub fn percentage(&self) -> CSSFloat {
self.percentage.unwrap_or(0.)
}
}

impl ::cssparser::ToCss for Calc {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match (self.length, self.percentage) {
(None, Some(p)) => write!(dest, "{}%", p),
(Some(l), None) => write!(dest, "{}px", Au::to_px(l)),
(Some(l), Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.),
_ => unreachable!()
}
}
}

impl ToComputedValue for specified::Calc {
type ComputedValue = Calc;

fn to_computed_value(&self, context: &Context) -> Calc {
let length = self.absolute;
let percentage = self.percentage;

Calc { length: length, percentage: percentage }
}
}


#[derive(PartialEq, Clone, Copy, HeapSizeOf)]
pub enum LengthOrPercentage {
Length(Au),
Percentage(CSSFloat),
Calc(Calc),
}

impl LengthOrPercentage {
@@ -955,6 +1082,8 @@ pub mod computed {
match self {
&LengthOrPercentage::Length(length) => write!(f, "{:?}", length),
&LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
// XXX HACK WRONG
&LengthOrPercentage::Calc(calc) => write!(f, "{}%", 100.),
}
}
}
@@ -970,6 +1099,9 @@ pub mod computed {
specified::LengthOrPercentage::Percentage(value) => {
LengthOrPercentage::Percentage(value)
}
specified::LengthOrPercentage::Calc(calc) => {
LengthOrPercentage::Calc(calc.to_computed_value(context))
}
}
}
}
@@ -980,6 +1112,7 @@ pub mod computed {
&LengthOrPercentage::Length(length) => length.to_css(dest),
&LengthOrPercentage::Percentage(percentage)
=> write!(dest, "{}%", percentage * 100.),
&LengthOrPercentage::Calc(calc) => calc.to_css(dest),
}
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.