Port servo to the new media query system.

Port `width`, and also add the `scan` media feature so I don't need to add
ugliness just to workaround the unused keyword_evaluator macro.
This commit is contained in:
Emilio Cobos Álvarez 2018-08-18 18:19:34 +02:00
parent 8ae1322fb3
commit 935b5393a9
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
3 changed files with 57 additions and 134 deletions

View file

@ -16,17 +16,6 @@ use media_queries::media_feature::{MediaFeatureDescription, Evaluator};
use media_queries::media_feature::{AllowsRanges, ParsingRequirements};
use media_queries::media_feature_expression::{AspectRatio, RangeOrOperator};
macro_rules! feature {
($name:expr, $allows_ranges:expr, $evaluator:expr, $reqs:expr,) => {
MediaFeatureDescription {
name: $name,
allows_ranges: $allows_ranges,
evaluator: $evaluator,
requirements: $reqs,
}
}
}
fn viewport_size(device: &Device) -> Size2D<Au> {
let pc = device.pres_context();
if pc.mIsRootPaginatedDocument() != 0 {

View file

@ -161,6 +161,18 @@ impl MediaFeatureDescription {
}
}
/// A simple helper to construct a `MediaFeatureDescription`.
macro_rules! feature {
($name:expr, $allows_ranges:expr, $evaluator:expr, $reqs:expr,) => {
$crate::media_queries::media_feature::MediaFeatureDescription {
name: $name,
allows_ranges: $allows_ranges,
evaluator: $evaluator,
requirements: $reqs,
}
}
}
impl fmt::Debug for MediaFeatureDescription {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("MediaFeatureExpression")

View file

@ -5,21 +5,21 @@
//! Servo's media-query device and expression representation.
use app_units::Au;
use context::QuirksMode;
use cssparser::{Parser, RGBA};
use cssparser::RGBA;
use euclid::{Size2D, TypedScale, TypedSize2D};
use media_queries::MediaType;
use parser::ParserContext;
use properties::ComputedValues;
use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write};
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
use style_traits::{CSSPixel, CssWriter, DevicePixel, ParseError, ToCss};
use style_traits::{CSSPixel, DevicePixel};
use style_traits::viewport::ViewportConstraints;
use values::{specified, KeyframesName};
use values::computed::{self, ToComputedValue};
use values::KeyframesName;
use values::computed::CSSPixelLength;
use values::computed::font::FontSize;
use media_queries::media_feature::{MediaFeatureDescription, Evaluator};
use media_queries::media_feature::{AllowsRanges, ParsingRequirements};
use media_queries::media_feature_expression::RangeOrOperator;
/// A device is a structure that represents the current media a given document
/// is displayed in.
///
@ -155,125 +155,47 @@ impl Device {
}
}
/// A expression kind servo understands and parses.
///
/// Only `pub` for unit testing, please don't use it directly!
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub enum ExpressionKind {
/// <http://dev.w3.org/csswg/mediaqueries-3/#width>
Width(Range<specified::Length>),
/// https://drafts.csswg.org/mediaqueries-4/#width
fn eval_width(
device: &Device,
value: Option<CSSPixelLength>,
range_or_operator: Option<RangeOrOperator>,
) -> bool {
RangeOrOperator::evaluate(
range_or_operator,
value.map(Au::from),
device.au_viewport_size().width,
)
}
/// A single expression a per:
///
/// <http://dev.w3.org/csswg/mediaqueries-3/#media1>
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub struct MediaFeatureExpression(pub ExpressionKind);
impl MediaFeatureExpression {
/// The kind of expression we're, just for unit testing.
///
/// Eventually this will become servo-only.
pub fn kind_for_testing(&self) -> &ExpressionKind {
&self.0
}
/// Parse a media expression of the form:
///
/// ```
/// media-feature: media-value
/// ```
///
/// Only supports width ranges for now.
pub fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
input.expect_parenthesis_block()?;
input.parse_nested_block(|input| {
Self::parse_in_parenthesis_block(context, input)
})
}
/// Parse a media range expression where we've already consumed the
/// parenthesis.
pub fn parse_in_parenthesis_block<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let name = input.expect_ident_cloned()?;
input.expect_colon()?;
// TODO: Handle other media features
Ok(MediaFeatureExpression(match_ignore_ascii_case! { &name,
"min-width" => {
ExpressionKind::Width(Range::Min(specified::Length::parse_non_negative(context, input)?))
},
"max-width" => {
ExpressionKind::Width(Range::Max(specified::Length::parse_non_negative(context, input)?))
},
"width" => {
ExpressionKind::Width(Range::Eq(specified::Length::parse_non_negative(context, input)?))
},
_ => return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone())))
}))
}
/// Evaluate this expression and return whether it matches the current
/// device.
pub fn matches(&self, device: &Device, quirks_mode: QuirksMode) -> bool {
let viewport_size = device.au_viewport_size();
let value = viewport_size.width;
match self.0 {
ExpressionKind::Width(ref range) => {
match range.to_computed_range(device, quirks_mode) {
Range::Min(ref width) => value >= *width,
Range::Max(ref width) => value <= *width,
Range::Eq(ref width) => value == *width,
}
},
}
}
#[derive(Debug, Copy, Clone, FromPrimitive, ToCss, Parse)]
#[repr(u8)]
enum Scan {
Progressive,
Interlace,
}
impl ToCss for MediaFeatureExpression {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
let (s, l) = match self.0 {
ExpressionKind::Width(Range::Min(ref l)) => ("(min-width: ", l),
ExpressionKind::Width(Range::Max(ref l)) => ("(max-width: ", l),
ExpressionKind::Width(Range::Eq(ref l)) => ("(width: ", l),
};
dest.write_str(s)?;
l.to_css(dest)?;
dest.write_char(')')
}
/// https://drafts.csswg.org/mediaqueries-4/#scan
fn eval_scan(_: &Device, _: Option<Scan>) -> bool {
// Since we doesn't support the 'tv' media type, the 'scan' feature never
// matches.
false
}
/// An enumeration that represents a ranged value.
///
/// Only public for testing, implementation details of `MediaFeatureExpression`
/// may change for Stylo.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub enum Range<T> {
/// At least the inner value.
Min(T),
/// At most the inner value.
Max(T),
/// Exactly the inner value.
Eq(T),
}
impl Range<specified::Length> {
fn to_computed_range(&self, device: &Device, quirks_mode: QuirksMode) -> Range<Au> {
computed::Context::for_media_query_evaluation(device, quirks_mode, |context| match *self {
Range::Min(ref width) => Range::Min(Au::from(width.to_computed_value(&context))),
Range::Max(ref width) => Range::Max(Au::from(width.to_computed_value(&context))),
Range::Eq(ref width) => Range::Eq(Au::from(width.to_computed_value(&context))),
})
}
lazy_static! {
/// A list with all the media features that Servo supports.
pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 2] = [
feature!(
atom!("width"),
AllowsRanges::Yes,
Evaluator::Length(eval_width),
ParsingRequirements::empty(),
),
feature!(
atom!("scan"),
AllowsRanges::No,
keyword_evaluator!(eval_scan, Scan),
ParsingRequirements::empty(),
),
];
}