Auto merge of #19194 - emilio:media-query-calc, r=Manishearth

stylo: Bring back support for calc() in media-queries.

Bug: 1396057
Reviewed-by: Manishearth

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/19194)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-11-12 20:06:12 -06:00 committed by GitHub
commit 4970b5d154
2 changed files with 51 additions and 59 deletions

View file

@ -18,7 +18,7 @@ use gecko_bindings::structs::{nsMediaExpression_Range, nsMediaFeature};
use gecko_bindings::structs::{nsMediaFeature_ValueType, nsMediaFeature_RangeType}; use gecko_bindings::structs::{nsMediaFeature_ValueType, nsMediaFeature_RangeType};
use gecko_bindings::structs::{nsPresContext, RawGeckoPresContextOwned}; use gecko_bindings::structs::{nsPresContext, RawGeckoPresContextOwned};
use media_queries::MediaType; use media_queries::MediaType;
use parser::ParserContext; use parser::{Parse, ParserContext};
use properties::ComputedValues; use properties::ComputedValues;
use servo_arc::Arc; use servo_arc::Arc;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
@ -32,7 +32,7 @@ use stylesheets::Origin;
use values::{CSSFloat, CustomIdent}; use values::{CSSFloat, CustomIdent};
use values::computed::{self, ToComputedValue}; use values::computed::{self, ToComputedValue};
use values::computed::font::FontSize; use values::computed::font::FontSize;
use values::specified::Length; use values::specified::{Integer, Length, Number};
/// The `Device` in Gecko wraps a pres context, has a default values computed, /// The `Device` in Gecko wraps a pres context, has a default values computed,
/// and contains all the viewport rule state. /// and contains all the viewport rule state.
@ -307,6 +307,13 @@ impl Resolution {
} }
/// A value found or expected in a media expression. /// A value found or expected in a media expression.
///
/// FIXME(emilio): How should calc() serialize in the Number / Integer /
/// BoolInteger / IntRatio case, as computed or as specified value?
///
/// If the first, this would need to store the relevant values.
///
/// See: https://github.com/w3c/csswg-drafts/issues/1968
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum MediaExpressionValue { pub enum MediaExpressionValue {
/// A length. /// A length.
@ -439,7 +446,8 @@ impl MediaExpressionValue {
} }
fn find_feature<F>(mut f: F) -> Option<&'static nsMediaFeature> fn find_feature<F>(mut f: F) -> Option<&'static nsMediaFeature>
where F: FnMut(&'static nsMediaFeature) -> bool, where
F: FnMut(&'static nsMediaFeature) -> bool,
{ {
unsafe { unsafe {
let mut features = structs::nsMediaFeatures_features.as_ptr(); let mut features = structs::nsMediaFeatures_features.as_ptr();
@ -453,10 +461,12 @@ fn find_feature<F>(mut f: F) -> Option<&'static nsMediaFeature>
None None
} }
unsafe fn find_in_table<F>(mut current_entry: *const nsCSSProps_KTableEntry, unsafe fn find_in_table<F>(
mut f: F) mut current_entry: *const nsCSSProps_KTableEntry,
-> Option<(nsCSSKeyword, i16)> mut f: F,
where F: FnMut(nsCSSKeyword, i16) -> bool ) -> Option<(nsCSSKeyword, i16)>
where
F: FnMut(nsCSSKeyword, i16) -> bool
{ {
loop { loop {
let value = (*current_entry).mValue; let value = (*current_entry).mValue;
@ -474,66 +484,50 @@ unsafe fn find_in_table<F>(mut current_entry: *const nsCSSProps_KTableEntry,
} }
} }
fn parse_feature_value<'i, 't>(feature: &nsMediaFeature, fn parse_feature_value<'i, 't>(
feature_value_type: nsMediaFeature_ValueType, feature: &nsMediaFeature,
context: &ParserContext, feature_value_type: nsMediaFeature_ValueType,
input: &mut Parser<'i, 't>) context: &ParserContext,
-> Result<MediaExpressionValue, ParseError<'i>> { input: &mut Parser<'i, 't>,
) -> Result<MediaExpressionValue, ParseError<'i>> {
let value = match feature_value_type { let value = match feature_value_type {
nsMediaFeature_ValueType::eLength => { nsMediaFeature_ValueType::eLength => {
let length = Length::parse_non_negative(context, input)?; let length = Length::parse_non_negative(context, input)?;
// FIXME(canaltinova): See bug 1396057. Gecko doesn't support calc MediaExpressionValue::Length(length)
// inside media queries. This check is for temporarily remove it
// for parity with gecko. We should remove this check when we want
// to support it.
if let Length::Calc(_) = length {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
MediaExpressionValue::Length(length)
}, },
nsMediaFeature_ValueType::eInteger => { nsMediaFeature_ValueType::eInteger => {
// FIXME(emilio): We should use `Integer::parse` to handle `calc` let integer = Integer::parse_non_negative(context, input)?;
// properly in integer expressions. Note that calc is still not MediaExpressionValue::Integer(integer.value() as u32)
// supported in media queries per FIXME above.
let i = input.expect_integer()?;
if i < 0 {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
MediaExpressionValue::Integer(i as u32)
} }
nsMediaFeature_ValueType::eBoolInteger => { nsMediaFeature_ValueType::eBoolInteger => {
let i = input.expect_integer()?; let integer = Integer::parse_non_negative(context, input)?;
if i < 0 || i > 1 { let value = integer.value();
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) if value > 1 {
} return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
MediaExpressionValue::BoolInteger(i == 1) }
MediaExpressionValue::BoolInteger(value == 1)
} }
nsMediaFeature_ValueType::eFloat => { nsMediaFeature_ValueType::eFloat => {
MediaExpressionValue::Float(input.expect_number()?) let number = Number::parse(context, input)?;
MediaExpressionValue::Float(number.get())
} }
nsMediaFeature_ValueType::eIntRatio => { nsMediaFeature_ValueType::eIntRatio => {
let a = input.expect_integer()?; let a = Integer::parse_positive(context, input)?;
if a <= 0 { input.expect_delim('/')?;
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) let b = Integer::parse_positive(context, input)?;
} MediaExpressionValue::IntRatio(a.value() as u32, b.value() as u32)
input.expect_delim('/')?;
let b = input.expect_integer()?;
if b <= 0 {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
MediaExpressionValue::IntRatio(a as u32, b as u32)
} }
nsMediaFeature_ValueType::eResolution => { nsMediaFeature_ValueType::eResolution => {
MediaExpressionValue::Resolution(Resolution::parse(input)?) MediaExpressionValue::Resolution(Resolution::parse(input)?)
} }
nsMediaFeature_ValueType::eEnumerated => { nsMediaFeature_ValueType::eEnumerated => {
let location = input.current_source_location(); let location = input.current_source_location();
let keyword = input.expect_ident()?; let keyword = input.expect_ident()?;
let keyword = unsafe { let keyword = unsafe {
bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), bindings::Gecko_LookupCSSKeyword(
keyword.len() as u32) keyword.as_bytes().as_ptr(),
keyword.len() as u32,
)
}; };
let first_table_entry: *const nsCSSProps_KTableEntry = unsafe { let first_table_entry: *const nsCSSProps_KTableEntry = unsafe {
@ -557,14 +551,12 @@ fn parse_feature_value<'i, 't>(feature: &nsMediaFeature,
impl Expression { impl Expression {
/// Trivially construct a new expression. /// Trivially construct a new expression.
fn new(feature: &'static nsMediaFeature, fn new(
value: Option<MediaExpressionValue>, feature: &'static nsMediaFeature,
range: nsMediaExpression_Range) -> Self { value: Option<MediaExpressionValue>,
Expression { range: nsMediaExpression_Range,
feature: feature, ) -> Self {
value: value, Self { feature, value, range }
range: range,
}
} }
/// Parse a media expression of the form: /// Parse a media expression of the form:

View file

@ -185,7 +185,7 @@ impl FontRelativeLength {
// element, the rem units refer to the propertys initial // element, the rem units refer to the propertys initial
// value. // value.
// //
let reference_size = if context.is_root_element { let reference_size = if context.is_root_element || context.in_media_query {
reference_font_size reference_font_size
} else { } else {
context.device().root_font_size() context.device().root_font_size()