mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
style: Isolate the soon-to-be style-backend-specific from the media_query module.
This commit is contained in:
parent
7788f43c7e
commit
c0cf847043
9 changed files with 389 additions and 318 deletions
|
@ -4,13 +4,18 @@
|
|||
|
||||
//! Gecko-specific style-system bits.
|
||||
|
||||
pub mod conversions;
|
||||
pub mod data;
|
||||
|
||||
// TODO(emilio): Implement Gecko media query parsing and evaluation using
|
||||
// nsMediaFeatures.
|
||||
#[path = "../servo/media_queries.rs"]
|
||||
pub mod media_queries;
|
||||
|
||||
pub mod restyle_damage;
|
||||
pub mod selector_parser;
|
||||
pub mod snapshot;
|
||||
pub mod snapshot_helpers;
|
||||
pub mod traversal;
|
||||
pub mod wrapper;
|
||||
|
||||
pub mod conversions;
|
||||
pub mod selector_parser;
|
||||
pub mod values;
|
||||
pub mod wrapper;
|
||||
|
|
|
@ -110,7 +110,6 @@ pub mod keyframes;
|
|||
#[allow(missing_docs)] // TODO.
|
||||
pub mod logical_geometry;
|
||||
pub mod matching;
|
||||
#[allow(missing_docs)]
|
||||
pub mod media_queries;
|
||||
pub mod owning_handle;
|
||||
pub mod parallel;
|
||||
|
|
|
@ -7,22 +7,22 @@
|
|||
//! [mq]: https://drafts.csswg.org/mediaqueries/
|
||||
|
||||
use Atom;
|
||||
use app_units::Au;
|
||||
use cssparser::{Delimiter, Parser, Token};
|
||||
use euclid::size::{Size2D, TypedSize2D};
|
||||
use properties::ComputedValues;
|
||||
use serialize_comma_separated_list;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "gecko")]
|
||||
use std::sync::Arc;
|
||||
use style_traits::{ToCss, ViewportPx};
|
||||
use values::computed::{self, ToComputedValue};
|
||||
use values::specified;
|
||||
use style_traits::ToCss;
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
pub use servo::media_queries::{Device, Expression};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use gecko::media_queries::{Device, Expression};
|
||||
|
||||
/// A type that encapsulates a media query list.
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct MediaList {
|
||||
/// The list of media queries.
|
||||
pub media_queries: Vec<MediaQuery>
|
||||
}
|
||||
|
||||
|
@ -40,59 +40,15 @@ impl Default for MediaList {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum Range<T> {
|
||||
Min(T),
|
||||
Max(T),
|
||||
Eq(T),
|
||||
}
|
||||
|
||||
impl Range<specified::Length> {
|
||||
fn to_computed_range(&self, viewport_size: Size2D<Au>, default_values: &ComputedValues) -> Range<Au> {
|
||||
// http://dev.w3.org/csswg/mediaqueries3/#units
|
||||
// em units are relative to the initial font-size.
|
||||
let context = computed::Context {
|
||||
is_root_element: false,
|
||||
viewport_size: viewport_size,
|
||||
inherited_style: default_values,
|
||||
// This cloning business is kind of dumb.... It's because Context
|
||||
// insists on having an actual ComputedValues inside itself.
|
||||
style: default_values.clone(),
|
||||
font_metrics_provider: None
|
||||
};
|
||||
|
||||
match *self {
|
||||
Range::Min(ref width) => Range::Min(width.to_computed_value(&context)),
|
||||
Range::Max(ref width) => Range::Max(width.to_computed_value(&context)),
|
||||
Range::Eq(ref width) => Range::Eq(width.to_computed_value(&context))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord> Range<T> {
|
||||
fn evaluate(&self, value: T) -> bool {
|
||||
match *self {
|
||||
Range::Min(ref width) => { value >= *width },
|
||||
Range::Max(ref width) => { value <= *width },
|
||||
Range::Eq(ref width) => { value == *width },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// http://dev.w3.org/csswg/mediaqueries-3/#media1
|
||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum Expression {
|
||||
/// http://dev.w3.org/csswg/mediaqueries-3/#width
|
||||
Width(Range<specified::Length>),
|
||||
}
|
||||
|
||||
/// http://dev.w3.org/csswg/mediaqueries-3/#media0
|
||||
/// https://drafts.csswg.org/mediaqueries/#mq-prefix
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum Qualifier {
|
||||
/// Hide a media query from legacy UAs:
|
||||
/// https://drafts.csswg.org/mediaqueries/#mq-only
|
||||
Only,
|
||||
/// Negate a media query:
|
||||
/// https://drafts.csswg.org/mediaqueries/#mq-not
|
||||
Not,
|
||||
}
|
||||
|
||||
|
@ -107,11 +63,17 @@ impl ToCss for Qualifier {
|
|||
}
|
||||
}
|
||||
|
||||
/// A [media query][mq].
|
||||
///
|
||||
/// [mq]: https://drafts.csswg.org/mediaqueries/
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct MediaQuery {
|
||||
/// The qualifier for this query.
|
||||
pub qualifier: Option<Qualifier>,
|
||||
/// The media type for this query, that can be known, unknown, or "all".
|
||||
pub media_type: MediaQueryType,
|
||||
/// The set of expressions that this media query contains.
|
||||
pub expressions: Vec<Expression>,
|
||||
}
|
||||
|
||||
|
@ -122,7 +84,9 @@ impl MediaQuery {
|
|||
Self::new(Some(Qualifier::Not), MediaQueryType::All, vec![])
|
||||
}
|
||||
|
||||
pub fn new(qualifier: Option<Qualifier>, media_type: MediaQueryType,
|
||||
/// Trivially constructs a new media query.
|
||||
pub fn new(qualifier: Option<Qualifier>,
|
||||
media_type: MediaQueryType,
|
||||
expressions: Vec<Expression>) -> MediaQuery {
|
||||
MediaQuery {
|
||||
qualifier: qualifier,
|
||||
|
@ -134,7 +98,7 @@ impl MediaQuery {
|
|||
|
||||
impl ToCss for MediaQuery {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||
where W: fmt::Write
|
||||
where W: fmt::Write,
|
||||
{
|
||||
if let Some(qual) = self.qualifier {
|
||||
try!(qual.to_css(dest));
|
||||
|
@ -165,19 +129,11 @@ impl ToCss for MediaQuery {
|
|||
try!(write!(dest, " and "));
|
||||
}
|
||||
|
||||
for (i, &e) in self.expressions.iter().enumerate() {
|
||||
try!(write!(dest, "("));
|
||||
let (mm, l) = match e {
|
||||
Expression::Width(Range::Min(ref l)) => ("min-", l),
|
||||
Expression::Width(Range::Max(ref l)) => ("max-", l),
|
||||
Expression::Width(Range::Eq(ref l)) => ("", l),
|
||||
};
|
||||
try!(write!(dest, "{}width: ", mm));
|
||||
try!(l.to_css(dest));
|
||||
try!(write!(dest, ")"));
|
||||
if i != self.expressions.len() - 1 {
|
||||
try!(write!(dest, " and "));
|
||||
}
|
||||
try!(self.expressions[0].to_css(dest));
|
||||
|
||||
for expr in self.expressions.iter().skip(1) {
|
||||
try!(write!(dest, " and "));
|
||||
try!(expr.to_css(dest));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -187,8 +143,11 @@ impl ToCss for MediaQuery {
|
|||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum MediaQueryType {
|
||||
All, // Always true
|
||||
/// A media type that matches every device.
|
||||
All,
|
||||
/// A known media type, that we parse and understand.
|
||||
Known(MediaType),
|
||||
/// An unknown media type.
|
||||
Unknown(Atom),
|
||||
}
|
||||
|
||||
|
@ -204,19 +163,22 @@ impl MediaQueryType {
|
|||
}
|
||||
}
|
||||
|
||||
fn matches(&self, other: &MediaType) -> bool {
|
||||
fn matches(&self, other: MediaType) -> bool {
|
||||
match *self {
|
||||
MediaQueryType::All => true,
|
||||
MediaQueryType::Known(ref known_type) => known_type == other,
|
||||
MediaQueryType::Known(ref known_type) => *known_type == other,
|
||||
MediaQueryType::Unknown(..) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/mediaqueries/#media-types
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum MediaType {
|
||||
/// The "screen" media type.
|
||||
Screen,
|
||||
/// The "print" media type.
|
||||
Print,
|
||||
}
|
||||
|
||||
|
@ -229,77 +191,10 @@ impl MediaType {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct Device {
|
||||
pub media_type: MediaType,
|
||||
pub viewport_size: TypedSize2D<f32, ViewportPx>,
|
||||
#[cfg(feature = "gecko")]
|
||||
pub default_values: Arc<ComputedValues>,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn new(media_type: MediaType, viewport_size: TypedSize2D<f32, ViewportPx>) -> Device {
|
||||
Device {
|
||||
media_type: media_type,
|
||||
viewport_size: viewport_size,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn default_values(&self) -> &ComputedValues {
|
||||
ComputedValues::initial_values()
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
pub fn new(media_type: MediaType, viewport_size: TypedSize2D<f32, ViewportPx>,
|
||||
default_values: &Arc<ComputedValues>) -> Device {
|
||||
Device {
|
||||
media_type: media_type,
|
||||
viewport_size: viewport_size,
|
||||
default_values: default_values.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
pub fn default_values(&self) -> &ComputedValues {
|
||||
&*self.default_values
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn au_viewport_size(&self) -> Size2D<Au> {
|
||||
Size2D::new(Au::from_f32_px(self.viewport_size.width),
|
||||
Au::from_f32_px(self.viewport_size.height))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
fn parse(input: &mut Parser) -> Result<Expression, ()> {
|
||||
try!(input.expect_parenthesis_block());
|
||||
input.parse_nested_block(|input| {
|
||||
let name = try!(input.expect_ident());
|
||||
try!(input.expect_colon());
|
||||
// TODO: Handle other media features
|
||||
match_ignore_ascii_case! { name,
|
||||
"min-width" => {
|
||||
Ok(Expression::Width(Range::Min(try!(specified::Length::parse_non_negative(input)))))
|
||||
},
|
||||
"max-width" => {
|
||||
Ok(Expression::Width(Range::Max(try!(specified::Length::parse_non_negative(input)))))
|
||||
},
|
||||
"width" => {
|
||||
Ok(Expression::Width(Range::Eq(try!(specified::Length::parse_non_negative(input)))))
|
||||
},
|
||||
_ => Err(())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl MediaQuery {
|
||||
/// Parse a media query given css input.
|
||||
///
|
||||
/// Returns an error if any of the expressions is unknown.
|
||||
pub fn parse(input: &mut Parser) -> Result<MediaQuery, ()> {
|
||||
let mut expressions = vec![];
|
||||
|
||||
|
@ -336,43 +231,61 @@ impl MediaQuery {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse a media query list from CSS.
|
||||
///
|
||||
/// Always returns a media query list. If any invalid media query is found, the
|
||||
/// media query list is only filled with the equivalent of "not all", see:
|
||||
///
|
||||
/// https://drafts.csswg.org/mediaqueries/#error-handling
|
||||
pub fn parse_media_query_list(input: &mut Parser) -> MediaList {
|
||||
if input.is_exhausted() {
|
||||
return Default::default()
|
||||
}
|
||||
|
||||
let mut media_queries = vec![];
|
||||
let mut found_invalid = false;
|
||||
loop {
|
||||
media_queries.push(
|
||||
input.parse_until_before(Delimiter::Comma, MediaQuery::parse).ok()
|
||||
.unwrap_or_else(MediaQuery::never_matching));
|
||||
match input.parse_until_before(Delimiter::Comma, MediaQuery::parse) {
|
||||
Ok(mq) => if !found_invalid {
|
||||
media_queries.push(mq);
|
||||
},
|
||||
Err(..) => if !found_invalid {
|
||||
media_queries.clear();
|
||||
media_queries.push(MediaQuery::never_matching());
|
||||
// Consume the rest of the input as if they were valid
|
||||
// expressions (they might be, they might not), but ignore the
|
||||
// result, this allows correctly parsing invalid media queries.
|
||||
found_invalid = true;
|
||||
},
|
||||
}
|
||||
|
||||
match input.next() {
|
||||
Ok(Token::Comma) => {},
|
||||
Ok(_) => unreachable!(),
|
||||
Err(()) => break,
|
||||
}
|
||||
}
|
||||
|
||||
debug_assert!(!found_invalid || media_queries.len() == 1);
|
||||
|
||||
MediaList {
|
||||
media_queries: media_queries,
|
||||
}
|
||||
}
|
||||
|
||||
impl MediaList {
|
||||
/// Evaluate a whole `MediaList` against `Device`.
|
||||
pub fn evaluate(&self, device: &Device) -> bool {
|
||||
let viewport_size = device.au_viewport_size();
|
||||
|
||||
// Check if it is an empty media query list or any queries match (OR condition)
|
||||
// https://drafts.csswg.org/mediaqueries-4/#mq-list
|
||||
self.media_queries.is_empty() || self.media_queries.iter().any(|mq| {
|
||||
let media_match = mq.media_type.matches(&device.media_type);
|
||||
let media_match = mq.media_type.matches(device.media_type());
|
||||
|
||||
// Check if all conditions match (AND condition)
|
||||
let query_match = media_match && mq.expressions.iter().all(|expression| {
|
||||
match *expression {
|
||||
Expression::Width(ref value) =>
|
||||
value.to_computed_range(viewport_size, device.default_values()).evaluate(viewport_size.width),
|
||||
}
|
||||
});
|
||||
let query_match =
|
||||
media_match &&
|
||||
mq.expressions.iter()
|
||||
.all(|expression| expression.matches(&device));
|
||||
|
||||
// Apply the logical NOT qualifier to the result
|
||||
match mq.qualifier {
|
||||
|
@ -382,6 +295,7 @@ impl MediaList {
|
|||
})
|
||||
}
|
||||
|
||||
/// Whether this `MediaList` contains no media queries.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.media_queries.is_empty()
|
||||
}
|
||||
|
|
224
components/style/servo/media_queries.rs
Normal file
224
components/style/servo/media_queries.rs
Normal file
|
@ -0,0 +1,224 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Servo's media-query device and expression representation.
|
||||
|
||||
use app_units::Au;
|
||||
use cssparser::Parser;
|
||||
use euclid::{Size2D, TypedSize2D};
|
||||
use media_queries::MediaType;
|
||||
use properties::ComputedValues;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "gecko")]
|
||||
use std::sync::Arc;
|
||||
use style_traits::{ToCss, ViewportPx};
|
||||
use style_traits::viewport::ViewportConstraints;
|
||||
use values::computed::{self, ToComputedValue};
|
||||
use values::specified;
|
||||
|
||||
/// A device is a structure that represents the current media a given document
|
||||
/// is displayed in.
|
||||
///
|
||||
/// This is the struct against which media queries are evaluated.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct Device {
|
||||
/// The current media type used by de device.
|
||||
media_type: MediaType,
|
||||
/// The current viewport size, in viewport pixels.
|
||||
viewport_size: TypedSize2D<f32, ViewportPx>,
|
||||
/// A set of default computed values for this document.
|
||||
///
|
||||
/// This allows handling zoom correctly, among other things. Gecko-only for
|
||||
/// now, see #14773.
|
||||
#[cfg(feature = "gecko")]
|
||||
default_values: Arc<ComputedValues>,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
/// Trivially construct a new `Device`.
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn new(media_type: MediaType,
|
||||
viewport_size: TypedSize2D<f32, ViewportPx>)
|
||||
-> Device {
|
||||
Device {
|
||||
media_type: media_type,
|
||||
viewport_size: viewport_size,
|
||||
}
|
||||
}
|
||||
|
||||
/// Trivially construct a new `Device`.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub fn new(media_type:
|
||||
MediaType, viewport_size: TypedSize2D<f32, ViewportPx>,
|
||||
default_values: &Arc<ComputedValues>) -> Device {
|
||||
Device {
|
||||
media_type: media_type,
|
||||
viewport_size: viewport_size,
|
||||
default_values: default_values.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the default computed values for this device.
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn default_values(&self) -> &ComputedValues {
|
||||
ComputedValues::initial_values()
|
||||
}
|
||||
|
||||
/// Return the default computed values for this device.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub fn default_values(&self) -> &ComputedValues {
|
||||
&*self.default_values
|
||||
}
|
||||
|
||||
/// Returns the viewport size of the current device in app units, needed,
|
||||
/// among other things, to resolve viewport units.
|
||||
#[inline]
|
||||
pub fn au_viewport_size(&self) -> Size2D<Au> {
|
||||
Size2D::new(Au::from_f32_px(self.viewport_size.width),
|
||||
Au::from_f32_px(self.viewport_size.height))
|
||||
}
|
||||
|
||||
/// Returns the viewport size in pixels.
|
||||
#[inline]
|
||||
pub fn px_viewport_size(&self) -> TypedSize2D<f32, ViewportPx> {
|
||||
self.viewport_size
|
||||
}
|
||||
|
||||
/// Take into account a viewport rule taken from the stylesheets.
|
||||
pub fn account_for_viewport_rule(&mut self, constraints: &ViewportConstraints) {
|
||||
self.viewport_size = constraints.size;
|
||||
}
|
||||
|
||||
/// Return the media type of the current device.
|
||||
pub fn media_type(&self) -> MediaType {
|
||||
self.media_type.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// A expression kind servo understands and parses.
|
||||
///
|
||||
/// Only `pub` for unit testing, please don't use it directly!
|
||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum ExpressionKind {
|
||||
/// http://dev.w3.org/csswg/mediaqueries-3/#width
|
||||
Width(Range<specified::Length>),
|
||||
}
|
||||
|
||||
/// A single expression a per:
|
||||
///
|
||||
/// http://dev.w3.org/csswg/mediaqueries-3/#media1
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct Expression(ExpressionKind);
|
||||
|
||||
impl Expression {
|
||||
/// 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 and width ranges for now.
|
||||
pub fn parse(input: &mut Parser) -> Result<Self, ()> {
|
||||
try!(input.expect_parenthesis_block());
|
||||
input.parse_nested_block(|input| {
|
||||
let name = try!(input.expect_ident());
|
||||
try!(input.expect_colon());
|
||||
// TODO: Handle other media features
|
||||
Ok(Expression(match_ignore_ascii_case! { name,
|
||||
"min-width" => {
|
||||
ExpressionKind::Width(Range::Min(try!(specified::Length::parse_non_negative(input))))
|
||||
},
|
||||
"max-width" => {
|
||||
ExpressionKind::Width(Range::Max(try!(specified::Length::parse_non_negative(input))))
|
||||
},
|
||||
"width" => {
|
||||
ExpressionKind::Width(Range::Eq(try!(specified::Length::parse_non_negative(input))))
|
||||
},
|
||||
_ => return Err(())
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
/// Evaluate this expression and return whether it matches the current
|
||||
/// device.
|
||||
pub fn matches(&self, device: &Device) -> 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(viewport_size, device.default_values()) {
|
||||
Range::Min(ref width) => { value >= *width },
|
||||
Range::Max(ref width) => { value <= *width },
|
||||
Range::Eq(ref width) => { value == *width },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for Expression {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||
where W: fmt::Write,
|
||||
{
|
||||
try!(write!(dest, "("));
|
||||
let (mm, l) = match self.0 {
|
||||
ExpressionKind::Width(Range::Min(ref l)) => ("min-", l),
|
||||
ExpressionKind::Width(Range::Max(ref l)) => ("max-", l),
|
||||
ExpressionKind::Width(Range::Eq(ref l)) => ("", l),
|
||||
};
|
||||
try!(write!(dest, "{}width: ", mm));
|
||||
try!(l.to_css(dest));
|
||||
write!(dest, ")")
|
||||
}
|
||||
}
|
||||
|
||||
/// An enumeration that represents a ranged value.
|
||||
///
|
||||
/// Only public for testing, implementation details of `Expression` may change
|
||||
/// for Stylo.
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
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,
|
||||
viewport_size: Size2D<Au>,
|
||||
default_values: &ComputedValues)
|
||||
-> Range<Au> {
|
||||
// http://dev.w3.org/csswg/mediaqueries3/#units
|
||||
// em units are relative to the initial font-size.
|
||||
let context = computed::Context {
|
||||
is_root_element: false,
|
||||
viewport_size: viewport_size,
|
||||
inherited_style: default_values,
|
||||
// This cloning business is kind of dumb.... It's because Context
|
||||
// insists on having an actual ComputedValues inside itself.
|
||||
style: default_values.clone(),
|
||||
font_metrics_provider: None
|
||||
};
|
||||
|
||||
match *self {
|
||||
Range::Min(ref width) => Range::Min(width.to_computed_value(&context)),
|
||||
Range::Max(ref width) => Range::Max(width.to_computed_value(&context)),
|
||||
Range::Eq(ref width) => Range::Eq(width.to_computed_value(&context))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,5 +6,6 @@
|
|||
//!
|
||||
//! These get compiled out on a Gecko build.
|
||||
|
||||
pub mod media_queries;
|
||||
pub mod restyle_damage;
|
||||
pub mod selector_parser;
|
||||
|
|
|
@ -12,8 +12,6 @@ use dom::{PresentationalHintsSynthetizer, TElement};
|
|||
use error_reporting::StdoutErrorReporter;
|
||||
use keyframes::KeyframesAnimation;
|
||||
use media_queries::Device;
|
||||
#[cfg(feature = "servo")]
|
||||
use media_queries::MediaType;
|
||||
use parking_lot::RwLock;
|
||||
use properties::{self, CascadeFlags, ComputedValues, INHERIT_ALL, Importance};
|
||||
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||
|
@ -36,7 +34,6 @@ use std::slice;
|
|||
use std::sync::Arc;
|
||||
use style_traits::viewport::ViewportConstraints;
|
||||
use stylesheets::{CssRule, Origin, StyleRule, Stylesheet, UserAgentStylesheets};
|
||||
#[cfg(feature = "servo")]
|
||||
use viewport::{self, MaybeNew, ViewportRule};
|
||||
|
||||
pub use ::fnv::FnvHashMap;
|
||||
|
@ -389,20 +386,24 @@ impl Stylist {
|
|||
/// This means that we may need to rebuild style data even if the
|
||||
/// stylesheets haven't changed.
|
||||
///
|
||||
/// Viewport_Constraints::maybe_new is servo-only (see the comment above it
|
||||
/// explaining why), so we need to be servo-only too, since we call it.
|
||||
#[cfg(feature = "servo")]
|
||||
/// Also, the device that arrives here may need to take the viewport rules
|
||||
/// into account.
|
||||
///
|
||||
/// TODO(emilio): Probably should be unified with `update`, right now I
|
||||
/// don't think we take into account dynamic updates to viewport rules.
|
||||
///
|
||||
/// Probably worth to make the stylist own a single `Device`, and have a
|
||||
/// `update_device` function?
|
||||
pub fn set_device(&mut self, mut device: Device, stylesheets: &[Arc<Stylesheet>]) {
|
||||
let cascaded_rule = ViewportRule {
|
||||
declarations: viewport::Cascade::from_stylesheets(stylesheets, &device).finish(),
|
||||
};
|
||||
|
||||
self.viewport_constraints = ViewportConstraints::maybe_new(device.viewport_size, &cascaded_rule);
|
||||
self.viewport_constraints =
|
||||
ViewportConstraints::maybe_new(&device, &cascaded_rule);
|
||||
|
||||
if let Some(ref constraints) = self.viewport_constraints {
|
||||
// FIXME(emilio): creating a device here works, but is not really
|
||||
// appropriate. I should get rid of this while doing the stylo media
|
||||
// query work.
|
||||
device = Device::new(MediaType::Screen, constraints.size);
|
||||
device.account_for_viewport_rule(constraints);
|
||||
}
|
||||
|
||||
fn mq_eval_changed(rules: &[CssRule], before: &Device, after: &Device) -> bool {
|
||||
|
|
|
@ -9,28 +9,21 @@
|
|||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
use app_units::Au;
|
||||
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
|
||||
use cssparser::ToCss as ParserToCss;
|
||||
#[cfg(feature = "servo")]
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
#[cfg(feature = "servo")]
|
||||
use euclid::size::Size2D;
|
||||
use euclid::size::TypedSize2D;
|
||||
use media_queries::Device;
|
||||
use parser::{ParserContext, log_css_error};
|
||||
#[cfg(feature = "servo")]
|
||||
use properties::ComputedValues;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::iter::Enumerate;
|
||||
use std::str::Chars;
|
||||
use style_traits::{ToCss, ViewportPx};
|
||||
use style_traits::ToCss;
|
||||
use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom};
|
||||
use stylesheets::{Stylesheet, Origin};
|
||||
#[cfg(feature = "servo")]
|
||||
use values::computed::{Context, ToComputedValue};
|
||||
use values::specified::{Length, LengthOrPercentageOrAuto, ViewportPercentageLength};
|
||||
|
||||
|
@ -606,18 +599,13 @@ impl Cascade {
|
|||
pub trait MaybeNew {
|
||||
/// Create a ViewportConstraints from a viewport size and a `@viewport`
|
||||
/// rule.
|
||||
fn maybe_new(initial_viewport: TypedSize2D<f32, ViewportPx>,
|
||||
fn maybe_new(device: &Device,
|
||||
rule: &ViewportRule)
|
||||
-> Option<ViewportConstraints>;
|
||||
}
|
||||
|
||||
/// MaybeNew for ViewportConstraints uses ComputedValues::initial_values which
|
||||
/// is servo-only (not present in gecko). Once it has been changed to properly
|
||||
/// use per-document initial computed values, or not use the initial computed
|
||||
/// values at all, it can go back to being compiled unconditionally.
|
||||
#[cfg(feature = "servo")]
|
||||
impl MaybeNew for ViewportConstraints {
|
||||
fn maybe_new(initial_viewport: TypedSize2D<f32, ViewportPx>,
|
||||
fn maybe_new(device: &Device,
|
||||
rule: &ViewportRule)
|
||||
-> Option<ViewportConstraints>
|
||||
{
|
||||
|
@ -695,15 +683,14 @@ impl MaybeNew for ViewportConstraints {
|
|||
//
|
||||
// Note: DEVICE-ADAPT § 5. states that relative length values are
|
||||
// resolved against initial values
|
||||
let initial_viewport = Size2D::new(Au::from_f32_px(initial_viewport.width),
|
||||
Au::from_f32_px(initial_viewport.height));
|
||||
|
||||
let initial_viewport = device.au_viewport_size();
|
||||
|
||||
// TODO(emilio): Stop cloning `ComputedValues` around!
|
||||
let context = Context {
|
||||
is_root_element: false,
|
||||
viewport_size: initial_viewport,
|
||||
inherited_style: ComputedValues::initial_values(),
|
||||
style: ComputedValues::initial_values().clone(),
|
||||
inherited_style: device.default_values(),
|
||||
style: device.default_values().clone(),
|
||||
font_metrics_provider: None, // TODO: Should have!
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue