mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
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:
parent
8ae1322fb3
commit
935b5393a9
3 changed files with 57 additions and 134 deletions
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue