mirror of
https://github.com/servo/servo.git
synced 2025-07-09 16:33:40 +01:00
Auto merge of #19126 - emilio:source-size-list, r=nox
style: Introduce SourceSizeList. This is part of the work for https://bugzilla.mozilla.org/show_bug.cgi?id=1408308. But this can just land now IMO, before I do the integration bits. <!-- 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/19126) <!-- Reviewable:end -->
This commit is contained in:
commit
0047c77f03
6 changed files with 142 additions and 69 deletions
|
@ -10,7 +10,6 @@ use context::QuirksMode;
|
||||||
use cssparser::{CssStringWriter, Parser, RGBA, Token, BasicParseErrorKind};
|
use cssparser::{CssStringWriter, Parser, RGBA, Token, BasicParseErrorKind};
|
||||||
use euclid::ScaleFactor;
|
use euclid::ScaleFactor;
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use font_metrics::get_metrics_provider_for_product;
|
|
||||||
use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
|
use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
|
||||||
use gecko_bindings::bindings;
|
use gecko_bindings::bindings;
|
||||||
use gecko_bindings::structs;
|
use gecko_bindings::structs;
|
||||||
|
@ -20,11 +19,9 @@ 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::ParserContext;
|
||||||
use properties::{ComputedValues, StyleBuilder};
|
use properties::ComputedValues;
|
||||||
use properties::longhands::font_size;
|
use properties::longhands::font_size;
|
||||||
use rule_cache::RuleCacheConditions;
|
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering};
|
||||||
use str::starts_with_ignore_ascii_case;
|
use str::starts_with_ignore_ascii_case;
|
||||||
|
@ -722,26 +719,8 @@ impl Expression {
|
||||||
self.feature.mRangeType == nsMediaFeature_RangeType::eMinMaxAllowed,
|
self.feature.mRangeType == nsMediaFeature_RangeType::eMinMaxAllowed,
|
||||||
"Whoops, wrong range");
|
"Whoops, wrong range");
|
||||||
|
|
||||||
let default_values = device.default_computed_values();
|
|
||||||
|
|
||||||
|
|
||||||
let provider = get_metrics_provider_for_product();
|
|
||||||
|
|
||||||
// http://dev.w3.org/csswg/mediaqueries3/#units
|
// http://dev.w3.org/csswg/mediaqueries3/#units
|
||||||
// em units are relative to the initial font-size.
|
// em units are relative to the initial font-size.
|
||||||
let mut conditions = RuleCacheConditions::default();
|
|
||||||
let context = computed::Context {
|
|
||||||
is_root_element: false,
|
|
||||||
builder: StyleBuilder::for_derived_style(device, default_values, None, None),
|
|
||||||
font_metrics_provider: &provider,
|
|
||||||
cached_system_font: None,
|
|
||||||
in_media_query: true,
|
|
||||||
quirks_mode,
|
|
||||||
for_smil_animation: false,
|
|
||||||
for_non_inherited_property: None,
|
|
||||||
rule_cache_conditions: RefCell::new(&mut conditions),
|
|
||||||
};
|
|
||||||
|
|
||||||
let required_value = match self.value {
|
let required_value = match self.value {
|
||||||
Some(ref v) => v,
|
Some(ref v) => v,
|
||||||
None => {
|
None => {
|
||||||
|
@ -750,7 +729,13 @@ impl Expression {
|
||||||
return match *actual_value {
|
return match *actual_value {
|
||||||
BoolInteger(v) => v,
|
BoolInteger(v) => v,
|
||||||
Integer(v) => v != 0,
|
Integer(v) => v != 0,
|
||||||
Length(ref l) => l.to_computed_value(&context).px() != 0.,
|
Length(ref l) => {
|
||||||
|
computed::Context::for_media_query_evaluation(
|
||||||
|
device,
|
||||||
|
quirks_mode,
|
||||||
|
|context| l.to_computed_value(&context).px() != 0.,
|
||||||
|
)
|
||||||
|
},
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -759,8 +744,10 @@ impl Expression {
|
||||||
// FIXME(emilio): Handle the possible floating point errors?
|
// FIXME(emilio): Handle the possible floating point errors?
|
||||||
let cmp = match (required_value, actual_value) {
|
let cmp = match (required_value, actual_value) {
|
||||||
(&Length(ref one), &Length(ref other)) => {
|
(&Length(ref one), &Length(ref other)) => {
|
||||||
|
computed::Context::for_media_query_evaluation(device, quirks_mode, |context| {
|
||||||
one.to_computed_value(&context).to_i32_au()
|
one.to_computed_value(&context).to_i32_au()
|
||||||
.cmp(&other.to_computed_value(&context).to_i32_au())
|
.cmp(&other.to_computed_value(&context).to_i32_au())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
(&Integer(one), &Integer(ref other)) => one.cmp(other),
|
(&Integer(one), &Integer(ref other)) => one.cmp(other),
|
||||||
(&BoolInteger(one), &BoolInteger(ref other)) => one.cmp(other),
|
(&BoolInteger(one), &BoolInteger(ref other)) => one.cmp(other),
|
||||||
|
|
|
@ -77,17 +77,10 @@ impl MediaQuery {
|
||||||
/// Return a media query that never matches, used for when we fail to parse
|
/// Return a media query that never matches, used for when we fail to parse
|
||||||
/// a given media query.
|
/// a given media query.
|
||||||
fn never_matching() -> Self {
|
fn never_matching() -> Self {
|
||||||
Self::new(Some(Qualifier::Not), MediaQueryType::All, vec![])
|
Self {
|
||||||
}
|
qualifier: Some(Qualifier::Not),
|
||||||
|
media_type: MediaQueryType::All,
|
||||||
/// Trivially constructs a new media query.
|
expressions: vec![],
|
||||||
pub fn new(qualifier: Option<Qualifier>,
|
|
||||||
media_type: MediaQueryType,
|
|
||||||
expressions: Vec<Expression>) -> MediaQuery {
|
|
||||||
MediaQuery {
|
|
||||||
qualifier: qualifier,
|
|
||||||
media_type: media_type,
|
|
||||||
expressions: expressions,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,9 +202,12 @@ impl MediaQuery {
|
||||||
|
|
||||||
let media_type = match input.try(|i| i.expect_ident_cloned()) {
|
let media_type = match input.try(|i| i.expect_ident_cloned()) {
|
||||||
Ok(ident) => {
|
Ok(ident) => {
|
||||||
let result: Result<_, ParseError> = MediaQueryType::parse(&*ident)
|
MediaQueryType::parse(&*ident)
|
||||||
.map_err(|()| input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())));
|
.map_err(|()| {
|
||||||
result?
|
input.new_custom_error(
|
||||||
|
SelectorParseErrorKind::UnexpectedIdent(ident.clone())
|
||||||
|
)
|
||||||
|
})?
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// Media type is only optional if qualifier is not specified.
|
// Media type is only optional if qualifier is not specified.
|
||||||
|
@ -229,7 +225,7 @@ impl MediaQuery {
|
||||||
// Parse any subsequent expressions
|
// Parse any subsequent expressions
|
||||||
loop {
|
loop {
|
||||||
if input.try(|input| input.expect_ident_matching("and")).is_err() {
|
if input.try(|input| input.expect_ident_matching("and")).is_err() {
|
||||||
return Ok(MediaQuery::new(qualifier, media_type, expressions))
|
return Ok(MediaQuery { qualifier, media_type, expressions })
|
||||||
}
|
}
|
||||||
expressions.push(Expression::parse(context, input)?)
|
expressions.push(Expression::parse(context, input)?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,11 @@ use app_units::Au;
|
||||||
use context::QuirksMode;
|
use context::QuirksMode;
|
||||||
use cssparser::{Parser, RGBA};
|
use cssparser::{Parser, RGBA};
|
||||||
use euclid::{ScaleFactor, Size2D, TypedSize2D};
|
use euclid::{ScaleFactor, Size2D, TypedSize2D};
|
||||||
use font_metrics::ServoMetricsProvider;
|
|
||||||
use media_queries::MediaType;
|
use media_queries::MediaType;
|
||||||
use parser::ParserContext;
|
use parser::ParserContext;
|
||||||
use properties::{ComputedValues, StyleBuilder};
|
use properties::ComputedValues;
|
||||||
use properties::longhands::font_size;
|
use properties::longhands::font_size;
|
||||||
use rule_cache::RuleCacheConditions;
|
|
||||||
use selectors::parser::SelectorParseErrorKind;
|
use selectors::parser::SelectorParseErrorKind;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
|
||||||
use style_traits::{CSSPixel, DevicePixel, ToCss, ParseError};
|
use style_traits::{CSSPixel, DevicePixel, ToCss, ParseError};
|
||||||
|
@ -252,29 +249,12 @@ pub enum Range<T> {
|
||||||
|
|
||||||
impl Range<specified::Length> {
|
impl Range<specified::Length> {
|
||||||
fn to_computed_range(&self, device: &Device, quirks_mode: QuirksMode) -> Range<Au> {
|
fn to_computed_range(&self, device: &Device, quirks_mode: QuirksMode) -> Range<Au> {
|
||||||
let default_values = device.default_computed_values();
|
computed::Context::for_media_query_evaluation(device, quirks_mode, |context| {
|
||||||
let mut conditions = RuleCacheConditions::default();
|
|
||||||
// http://dev.w3.org/csswg/mediaqueries3/#units
|
|
||||||
// em units are relative to the initial font-size.
|
|
||||||
let context = computed::Context {
|
|
||||||
is_root_element: false,
|
|
||||||
builder: StyleBuilder::for_derived_style(device, default_values, None, None),
|
|
||||||
// Servo doesn't support font metrics
|
|
||||||
// A real provider will be needed here once we do; since
|
|
||||||
// ch units can exist in media queries.
|
|
||||||
font_metrics_provider: &ServoMetricsProvider,
|
|
||||||
in_media_query: true,
|
|
||||||
cached_system_font: None,
|
|
||||||
quirks_mode,
|
|
||||||
for_smil_animation: false,
|
|
||||||
for_non_inherited_property: None,
|
|
||||||
rule_cache_conditions: RefCell::new(&mut conditions),
|
|
||||||
};
|
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Range::Min(ref width) => Range::Min(Au::from(width.to_computed_value(&context))),
|
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::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)))
|
Range::Eq(ref width) => Range::Eq(Au::from(width.to_computed_value(&context)))
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
use {Atom, Namespace};
|
use {Atom, Namespace};
|
||||||
use context::QuirksMode;
|
use context::QuirksMode;
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::{FontMetricsProvider, get_metrics_provider_for_product};
|
||||||
use media_queries::Device;
|
use media_queries::Device;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use properties;
|
use properties;
|
||||||
|
@ -136,6 +136,36 @@ pub struct Context<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Context<'a> {
|
impl<'a> Context<'a> {
|
||||||
|
/// Creates a suitable context for media query evaluation, in which
|
||||||
|
/// font-relative units compute against the system_font, and executes `f`
|
||||||
|
/// with it.
|
||||||
|
pub fn for_media_query_evaluation<F, R>(
|
||||||
|
device: &Device,
|
||||||
|
quirks_mode: QuirksMode,
|
||||||
|
f: F,
|
||||||
|
) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&Context) -> R
|
||||||
|
{
|
||||||
|
let mut conditions = RuleCacheConditions::default();
|
||||||
|
let default_values = device.default_computed_values();
|
||||||
|
let provider = get_metrics_provider_for_product();
|
||||||
|
|
||||||
|
let context = Context {
|
||||||
|
is_root_element: false,
|
||||||
|
builder: StyleBuilder::for_derived_style(device, default_values, None, None),
|
||||||
|
font_metrics_provider: &provider,
|
||||||
|
cached_system_font: None,
|
||||||
|
in_media_query: true,
|
||||||
|
quirks_mode,
|
||||||
|
for_smil_animation: false,
|
||||||
|
for_non_inherited_property: None,
|
||||||
|
rule_cache_conditions: RefCell::new(&mut conditions),
|
||||||
|
};
|
||||||
|
|
||||||
|
f(&context)
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the current element is the root element.
|
/// Whether the current element is the root element.
|
||||||
pub fn is_root_element(&self) -> bool {
|
pub fn is_root_element(&self) -> bool {
|
||||||
self.is_root_element
|
self.is_root_element
|
||||||
|
|
|
@ -76,6 +76,7 @@ pub mod length;
|
||||||
pub mod percentage;
|
pub mod percentage;
|
||||||
pub mod position;
|
pub mod position;
|
||||||
pub mod rect;
|
pub mod rect;
|
||||||
|
pub mod source_size_list;
|
||||||
pub mod svg;
|
pub mod svg;
|
||||||
pub mod table;
|
pub mod table;
|
||||||
pub mod text;
|
pub mod text;
|
||||||
|
|
79
components/style/values/specified/source_size_list.rs
Normal file
79
components/style/values/specified/source_size_list.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
//! https://html.spec.whatwg.org/multipage/#source-size-list
|
||||||
|
|
||||||
|
use app_units::Au;
|
||||||
|
use cssparser::Parser;
|
||||||
|
use media_queries::{Device, Expression as MediaExpression};
|
||||||
|
use parser::{Parse, ParserContext};
|
||||||
|
use selectors::context::QuirksMode;
|
||||||
|
use style_traits::ParseError;
|
||||||
|
use values::computed::{self, ToComputedValue};
|
||||||
|
use values::specified::Length;
|
||||||
|
|
||||||
|
/// A value for a `<source-size>`:
|
||||||
|
///
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#source-size
|
||||||
|
pub struct SourceSize {
|
||||||
|
condition: MediaExpression,
|
||||||
|
value: Length,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for SourceSize {
|
||||||
|
fn parse<'i, 't>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Self, ParseError<'i>> {
|
||||||
|
let condition = MediaExpression::parse(context, input)?;
|
||||||
|
let value = Length::parse_non_negative(context, input)?;
|
||||||
|
|
||||||
|
Ok(Self { condition, value })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A value for a `<source-size-list>`:
|
||||||
|
///
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#source-size-list
|
||||||
|
pub struct SourceSizeList {
|
||||||
|
source_sizes: Vec<SourceSize>,
|
||||||
|
value: Length,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SourceSizeList {
|
||||||
|
/// Evaluate this <source-size-list> to get the final viewport length.
|
||||||
|
pub fn evaluate(&self, device: &Device, quirks_mode: QuirksMode) -> Au {
|
||||||
|
let matching_source_size = self.source_sizes.iter().find(|source_size| {
|
||||||
|
source_size.condition.matches(device, quirks_mode)
|
||||||
|
});
|
||||||
|
|
||||||
|
computed::Context::for_media_query_evaluation(device, quirks_mode, |context| {
|
||||||
|
match matching_source_size {
|
||||||
|
Some(source_size) => {
|
||||||
|
source_size.value.to_computed_value(context)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.value.to_computed_value(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for SourceSizeList {
|
||||||
|
fn parse<'i, 't>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Self, ParseError<'i>> {
|
||||||
|
let source_sizes = input.try(|input| {
|
||||||
|
input.parse_comma_separated(|input| {
|
||||||
|
SourceSize::parse(context, input)
|
||||||
|
})
|
||||||
|
}).unwrap_or(vec![]);
|
||||||
|
|
||||||
|
let value = Length::parse_non_negative(context, input)?;
|
||||||
|
|
||||||
|
Ok(Self { source_sizes, value })
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue