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

[not ready for review yet] Allow calc expressions when parsing numbers #7308

Closed
wants to merge 17 commits into from
Closed
Changes from 1 commit
Commits
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 21, 2015
commit 731d9f059d73399c88c7fa831830a4826e6e4b79
@@ -329,9 +329,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),
@@ -340,6 +339,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,
};
@@ -1945,6 +1945,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)),
}
}

@@ -987,7 +987,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(),
}
}

@@ -705,7 +705,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 {
@@ -714,6 +714,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 {
@@ -723,6 +724,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.),
}
}
}
@@ -734,6 +737,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),
}
}
}
@@ -754,12 +758,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),
}
}
}
@@ -1858,7 +1862,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.