Bug 1837273 - Remove viewport rule code. r=Oriol

Turns out Servo doesn't need this either, see
https://github.com/servo/servo/pull/29850.

Differential Revision: https://phabricator.services.mozilla.com/D180264
This commit is contained in:
Emilio Cobos Álvarez 2023-06-08 11:20:53 +00:00
Родитель 2e06f92ba0
Коммит 20cac1714b
18 изменённых файлов: 3 добавлений и 1617 удалений

Просмотреть файл

@ -105,7 +105,6 @@ void ServoStyleRuleMap::RuleRemoved(StyleSheet& aStyleSheet,
case StyleCssRuleType::CounterStyle: case StyleCssRuleType::CounterStyle:
case StyleCssRuleType::FontFeatureValues: case StyleCssRuleType::FontFeatureValues:
case StyleCssRuleType::FontPaletteValues: case StyleCssRuleType::FontPaletteValues:
case StyleCssRuleType::Viewport:
break; break;
} }
} }
@ -152,7 +151,6 @@ void ServoStyleRuleMap::FillTableFromRule(css::Rule& aRule) {
case StyleCssRuleType::CounterStyle: case StyleCssRuleType::CounterStyle:
case StyleCssRuleType::FontFeatureValues: case StyleCssRuleType::FontFeatureValues:
case StyleCssRuleType::FontPaletteValues: case StyleCssRuleType::FontPaletteValues:
case StyleCssRuleType::Viewport:
break; break;
} }
} }

Просмотреть файл

@ -101,9 +101,6 @@ css::Rule* ServoCSSRuleList::GetRule(uint32_t aIndex) {
#undef CASE_RULE_LOCKED #undef CASE_RULE_LOCKED
#undef CASE_RULE_UNLOCKED #undef CASE_RULE_UNLOCKED
#undef CASE_RULE_WITH_PREFIX #undef CASE_RULE_WITH_PREFIX
case StyleCssRuleType::Viewport:
MOZ_ASSERT_UNREACHABLE("viewport is not implemented in Gecko");
return nullptr;
case StyleCssRuleType::Keyframe: case StyleCssRuleType::Keyframe:
MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here"); MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here");
return nullptr; return nullptr;
@ -278,9 +275,6 @@ void ServoCSSRuleList::SetRawContents(RefPtr<StyleLockedCssRules> aNewRules,
case StyleCssRuleType::Keyframe: case StyleCssRuleType::Keyframe:
MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here"); MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here");
break; break;
case StyleCssRuleType::Viewport:
MOZ_ASSERT_UNREACHABLE("Gecko doesn't implemente @viewport?");
break;
} }
#undef RULE_CASE_WITH_PREFIX #undef RULE_CASE_WITH_PREFIX
#undef RULE_CASE_LOCKED #undef RULE_CASE_LOCKED

Просмотреть файл

@ -1026,9 +1026,6 @@ void ServoStyleSet::RuleChangedInternal(StyleSheet& aSheet, css::Rule& aRule,
// @namespace and @import rules, and can't be mutated. // @namespace and @import rules, and can't be mutated.
case StyleCssRuleType::Namespace: case StyleCssRuleType::Namespace:
break; break;
case StyleCssRuleType::Viewport:
MOZ_ASSERT_UNREACHABLE("Gecko doesn't implement @viewport");
break;
case StyleCssRuleType::Keyframe: case StyleCssRuleType::Keyframe:
// FIXME: We should probably just forward to the parent @keyframes rule? I // FIXME: We should probably just forward to the parent @keyframes rule? I
// think that'd do the right thing, but meanwhile... // think that'd do the right thing, but meanwhile...

Просмотреть файл

@ -26,7 +26,6 @@ use euclid::{Scale, SideOffsets2D};
use servo_arc::Arc; use servo_arc::Arc;
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};
use std::{cmp, fmt}; use std::{cmp, fmt};
use style_traits::viewport::ViewportConstraints;
use style_traits::{CSSPixel, DevicePixel}; use style_traits::{CSSPixel, DevicePixel};
/// 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,
@ -135,12 +134,6 @@ impl Device {
NonNegativeLength::new(au.to_f32_px()) NonNegativeLength::new(au.to_f32_px())
} }
/// Tells the device that a new viewport rule has been found, and stores the
/// relevant viewport constraints.
pub fn account_for_viewport_rule(&mut self, _constraints: &ViewportConstraints) {
unreachable!("Gecko doesn't support @viewport");
}
/// Whether any animation name may be referenced from the style of any /// Whether any animation name may be referenced from the style of any
/// element. /// element.
pub fn animation_name_may_be_referenced(&self, name: &KeyframesName) -> bool { pub fn animation_name_may_be_referenced(&self, name: &KeyframesName) -> bool {

Просмотреть файл

@ -551,7 +551,6 @@ impl StylesheetInvalidationSet {
CounterStyle(..) | CounterStyle(..) |
Page(..) | Page(..) |
Property(..) | Property(..) |
Viewport(..) |
FontFeatureValues(..) | FontFeatureValues(..) |
FontPaletteValues(..) | FontPaletteValues(..) |
LayerStatement(..) | LayerStatement(..) |
@ -637,13 +636,9 @@ impl StylesheetInvalidationSet {
CounterStyle(..) | CounterStyle(..) |
Page(..) | Page(..) |
Property(..) | Property(..) |
Viewport(..) |
FontFeatureValues(..) | FontFeatureValues(..) |
FontPaletteValues(..) => { FontPaletteValues(..) => {
debug!( debug!(" > Found unsupported rule, marking the whole subtree invalid.");
" > Found unsupported rule, marking the whole subtree \
invalid."
);
// TODO(emilio): Can we do better here? // TODO(emilio): Can we do better here?
// //

Просмотреть файл

@ -18,7 +18,6 @@ use app_units::Au;
use euclid::default::Size2D as UntypedSize2D; use euclid::default::Size2D as UntypedSize2D;
use euclid::{Scale, SideOffsets2D, Size2D}; use euclid::{Scale, SideOffsets2D, Size2D};
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use style_traits::viewport::ViewportConstraints;
use style_traits::{CSSPixel, DevicePixel}; use style_traits::{CSSPixel, DevicePixel};
/// A device is a structure that represents the current media a given document /// A device is a structure that represents the current media a given document
@ -155,11 +154,6 @@ impl Device {
self.device_pixel_ratio self.device_pixel_ratio
} }
/// 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. /// Return the media type of the current device.
pub fn media_type(&self) -> MediaType { pub fn media_type(&self) -> MediaType {
self.media_type.clone() self.media_type.clone()

Просмотреть файл

@ -1,70 +0,0 @@
/* 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 https://mozilla.org/MPL/2.0/. */
//! Cascading at-rule types and traits
use crate::stylesheets::Origin;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
/// Computes the cascade precedence as according to
/// <http://dev.w3.org/csswg/css-cascade/#cascade-origin>
#[inline]
fn cascade_precendence(origin: Origin, important: bool) -> u8 {
match (origin, important) {
(Origin::UserAgent, true) => 1,
(Origin::User, true) => 2,
(Origin::Author, true) => 3,
(Origin::Author, false) => 4,
(Origin::User, false) => 5,
(Origin::UserAgent, false) => 6,
}
}
/// Cascading rule descriptor implementation.
/// This is only used for at-rules which can cascade. These are @viewport and
/// @page, although we don't currently implement @page as such.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
pub struct DescriptorDeclaration<T> {
/// Origin of the declaration
pub origin: Origin,
/// Declaration value
pub descriptor: T,
/// Indicates the presence of a !important property.
pub important: bool,
}
impl<T> DescriptorDeclaration<T> {
#[allow(missing_docs)]
pub fn new(origin: Origin, descriptor: T, important: bool) -> Self {
Self {
origin,
descriptor,
important,
}
}
/// Returns true iff self is equal or higher precedence to the other.
pub fn higher_or_equal_precendence(&self, other: &Self) -> bool {
let self_precedence = cascade_precendence(self.origin, self.important);
let other_precedence = cascade_precendence(other.origin, other.important);
self_precedence <= other_precedence
}
}
impl<T> ToCss for DescriptorDeclaration<T>
where
T: ToCss,
{
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.descriptor.to_css(dest)?;
if self.important {
dest.write_str(" !important")?;
}
dest.write_char(';')
}
}

Просмотреть файл

@ -4,7 +4,6 @@
//! Style sheets and their CSS rules. //! Style sheets and their CSS rules.
mod cascading_at_rule;
pub mod container_rule; pub mod container_rule;
mod counter_style_rule; mod counter_style_rule;
mod document_rule; mod document_rule;
@ -26,7 +25,6 @@ mod rules_iterator;
mod style_rule; mod style_rule;
mod stylesheet; mod stylesheet;
pub mod supports_rule; pub mod supports_rule;
pub mod viewport_rule;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::gecko_bindings::sugar::refptr::RefCounted; use crate::gecko_bindings::sugar::refptr::RefCounted;
@ -74,7 +72,6 @@ pub use self::stylesheet::{AllowImportRules, SanitizationData, SanitizationKind}
pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet}; pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet};
pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets}; pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets};
pub use self::supports_rule::SupportsRule; pub use self::supports_rule::SupportsRule;
pub use self::viewport_rule::ViewportRule;
/// The CORS mode used for a CSS load. /// The CORS mode used for a CSS load.
#[repr(u8)] #[repr(u8)]
@ -256,7 +253,6 @@ pub enum CssRule {
FontFeatureValues(Arc<FontFeatureValuesRule>), FontFeatureValues(Arc<FontFeatureValuesRule>),
FontPaletteValues(Arc<FontPaletteValuesRule>), FontPaletteValues(Arc<FontPaletteValuesRule>),
CounterStyle(Arc<Locked<CounterStyleRule>>), CounterStyle(Arc<Locked<CounterStyleRule>>),
Viewport(Arc<ViewportRule>),
Keyframes(Arc<Locked<KeyframesRule>>), Keyframes(Arc<Locked<KeyframesRule>>),
Supports(Arc<SupportsRule>), Supports(Arc<SupportsRule>),
Page(Arc<Locked<PageRule>>), Page(Arc<Locked<PageRule>>),
@ -292,7 +288,6 @@ impl CssRule {
CssRule::FontFeatureValues(_) => 0, CssRule::FontFeatureValues(_) => 0,
CssRule::FontPaletteValues(_) => 0, CssRule::FontPaletteValues(_) => 0,
CssRule::CounterStyle(_) => 0, CssRule::CounterStyle(_) => 0,
CssRule::Viewport(_) => 0,
CssRule::Keyframes(_) => 0, CssRule::Keyframes(_) => 0,
CssRule::Supports(ref arc) => { CssRule::Supports(ref arc) => {
arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops) arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
@ -338,8 +333,6 @@ pub enum CssRuleType {
Document = 13, Document = 13,
// https://drafts.csswg.org/css-fonts/#om-fontfeaturevalues // https://drafts.csswg.org/css-fonts/#om-fontfeaturevalues
FontFeatureValues = 14, FontFeatureValues = 14,
// https://drafts.csswg.org/css-device-adapt/#css-rule-interface
Viewport = 15,
// After viewport, all rules should return 0 from the API, but we still need // After viewport, all rules should return 0 from the API, but we still need
// a constant somewhere. // a constant somewhere.
LayerBlock = 16, LayerBlock = 16,
@ -408,7 +401,6 @@ impl CssRule {
CssRule::CounterStyle(_) => CssRuleType::CounterStyle, CssRule::CounterStyle(_) => CssRuleType::CounterStyle,
CssRule::Keyframes(_) => CssRuleType::Keyframes, CssRule::Keyframes(_) => CssRuleType::Keyframes,
CssRule::Namespace(_) => CssRuleType::Namespace, CssRule::Namespace(_) => CssRuleType::Namespace,
CssRule::Viewport(_) => CssRuleType::Viewport,
CssRule::Supports(_) => CssRuleType::Supports, CssRule::Supports(_) => CssRuleType::Supports,
CssRule::Page(_) => CssRuleType::Page, CssRule::Page(_) => CssRuleType::Page,
CssRule::Property(_) => CssRuleType::Property, CssRule::Property(_) => CssRuleType::Property,
@ -507,7 +499,6 @@ impl DeepCloneWithLock for CssRule {
let rule = arc.read_with(guard); let rule = arc.read_with(guard);
CssRule::CounterStyle(Arc::new(lock.wrap(rule.clone()))) CssRule::CounterStyle(Arc::new(lock.wrap(rule.clone())))
}, },
CssRule::Viewport(ref arc) => CssRule::Viewport(arc.clone()),
CssRule::Keyframes(ref arc) => { CssRule::Keyframes(ref arc) => {
let rule = arc.read_with(guard); let rule = arc.read_with(guard);
CssRule::Keyframes(Arc::new( CssRule::Keyframes(Arc::new(
@ -550,7 +541,6 @@ impl ToCssWithGuard for CssRule {
CssRule::FontFeatureValues(ref rule) => rule.to_css(guard, dest), CssRule::FontFeatureValues(ref rule) => rule.to_css(guard, dest),
CssRule::FontPaletteValues(ref rule) => rule.to_css(guard, dest), CssRule::FontPaletteValues(ref rule) => rule.to_css(guard, dest),
CssRule::CounterStyle(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::CounterStyle(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Viewport(ref rule) => rule.to_css(guard, dest),
CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Media(ref rule) => rule.to_css(guard, dest), CssRule::Media(ref rule) => rule.to_css(guard, dest),
CssRule::Supports(ref rule) => rule.to_css(guard, dest), CssRule::Supports(ref rule) => rule.to_css(guard, dest),

Просмотреть файл

@ -25,10 +25,9 @@ use crate::stylesheets::keyframes_rule::parse_keyframe_list;
use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule}; use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule};
use crate::stylesheets::supports_rule::SupportsCondition; use crate::stylesheets::supports_rule::SupportsCondition;
use crate::stylesheets::{ use crate::stylesheets::{
viewport_rule, AllowImportRules, CorsMode, CssRule, CssRuleType, CssRules, DocumentRule, AllowImportRules, CorsMode, CssRule, CssRuleType, CssRules, DocumentRule,
FontFeatureValuesRule, FontPaletteValuesRule, KeyframesRule, MediaRule, NamespaceRule, FontFeatureValuesRule, FontPaletteValuesRule, KeyframesRule, MediaRule, NamespaceRule,
PageRule, PageSelectors, RulesMutateError, StyleRule, StylesheetLoader, SupportsRule, PageRule, PageSelectors, RulesMutateError, StyleRule, StylesheetLoader, SupportsRule,
ViewportRule,
}; };
use crate::values::computed::font::FamilyName; use crate::values::computed::font::FamilyName;
use crate::values::{CssUrl, CustomIdent, DashedIdent, KeyframesName}; use crate::values::{CssUrl, CustomIdent, DashedIdent, KeyframesName};
@ -197,8 +196,6 @@ pub enum AtRulePrelude {
Container(Arc<ContainerCondition>), Container(Arc<ContainerCondition>),
/// An @supports rule, with its conditional /// An @supports rule, with its conditional
Supports(SupportsCondition), Supports(SupportsCondition),
/// A @viewport rule prelude.
Viewport,
/// A @keyframes rule, with its animation name and vendor prefix if exists. /// A @keyframes rule, with its animation name and vendor prefix if exists.
Keyframes(KeyframesName, Option<VendorPrefix>), Keyframes(KeyframesName, Option<VendorPrefix>),
/// A @page rule prelude, with its page name if it exists. /// A @page rule prelude, with its page name if it exists.
@ -567,9 +564,6 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b, 'i> {
let name = parse_counter_style_name_definition(input)?; let name = parse_counter_style_name_definition(input)?;
AtRulePrelude::CounterStyle(name) AtRulePrelude::CounterStyle(name)
}, },
"viewport" if viewport_rule::enabled() => {
AtRulePrelude::Viewport
},
"keyframes" | "-webkit-keyframes" | "-moz-keyframes" => { "keyframes" | "-webkit-keyframes" | "-moz-keyframes" => {
let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") { let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") {
Some(VendorPrefix::WebKit) Some(VendorPrefix::WebKit)
@ -667,12 +661,6 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b, 'i> {
source_location, source_location,
})) }))
}, },
AtRulePrelude::Viewport => {
let body = self.nest_for_rule(CssRuleType::Viewport, |p| {
ViewportRule::parse(&p.context, input)
})?;
CssRule::Viewport(Arc::new(body))
},
AtRulePrelude::Keyframes(name, vendor_prefix) => { AtRulePrelude::Keyframes(name, vendor_prefix) => {
self.nest_for_rule(CssRuleType::Keyframe, |p| { self.nest_for_rule(CssRuleType::Keyframe, |p| {
CssRule::Keyframes(Arc::new(p.shared_lock.wrap(KeyframesRule { CssRule::Keyframes(Arc::new(p.shared_lock.wrap(KeyframesRule {

Просмотреть файл

@ -65,7 +65,6 @@ where
CssRule::Namespace(_) | CssRule::Namespace(_) |
CssRule::FontFace(_) | CssRule::FontFace(_) |
CssRule::CounterStyle(_) | CssRule::CounterStyle(_) |
CssRule::Viewport(_) |
CssRule::Keyframes(_) | CssRule::Keyframes(_) |
CssRule::Page(_) | CssRule::Page(_) |
CssRule::Property(_) | CssRule::Property(_) |

Просмотреть файл

@ -198,25 +198,6 @@ pub struct Stylesheet {
pub disabled: AtomicBool, pub disabled: AtomicBool,
} }
macro_rules! rule_filter {
($( $method: ident($variant:ident => $rule_type: ident), )+) => {
$(
#[allow(missing_docs)]
fn $method<F>(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F)
where F: FnMut(&crate::stylesheets::$rule_type),
{
use crate::stylesheets::CssRule;
for rule in self.effective_rules(device, guard) {
if let CssRule::$variant(ref rule) = *rule {
f(&rule)
}
}
}
)+
}
}
/// A trait to represent a given stylesheet in a document. /// A trait to represent a given stylesheet in a document.
pub trait StylesheetInDocument: ::std::fmt::Debug { pub trait StylesheetInDocument: ::std::fmt::Debug {
/// Get whether this stylesheet is enabled. /// Get whether this stylesheet is enabled.
@ -270,10 +251,6 @@ pub trait StylesheetInDocument: ::std::fmt::Debug {
) -> EffectiveRulesIterator<'a, 'b> { ) -> EffectiveRulesIterator<'a, 'b> {
self.iter_rules::<EffectiveRules>(device, guard) self.iter_rules::<EffectiveRules>(device, guard)
} }
rule_filter! {
effective_viewport_rules(Viewport => ViewportRule),
}
} }
impl StylesheetInDocument for Stylesheet { impl StylesheetInDocument for Stylesheet {
@ -367,7 +344,6 @@ impl SanitizationKind {
CssRule::Property(..) | CssRule::Property(..) |
CssRule::FontFeatureValues(..) | CssRule::FontFeatureValues(..) |
CssRule::FontPaletteValues(..) | CssRule::FontPaletteValues(..) |
CssRule::Viewport(..) |
CssRule::CounterStyle(..) => !is_standard, CssRule::CounterStyle(..) => !is_standard,
} }
} }

Просмотреть файл

@ -1,810 +0,0 @@
/* 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 https://mozilla.org/MPL/2.0/. */
//! The [`@viewport`][at] at-rule and [`meta`][meta] element.
//!
//! [at]: https://drafts.csswg.org/css-device-adapt/#atviewport-rule
//! [meta]: https://drafts.csswg.org/css-device-adapt/#viewport-meta
use crate::context::QuirksMode;
use crate::error_reporting::ContextualParseError;
use crate::media_queries::Device;
use crate::parser::{Parse, ParserContext};
use crate::properties::StyleBuilder;
use crate::rule_cache::RuleCacheConditions;
use crate::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard};
use crate::str::CssStringWriter;
use crate::stylesheets::cascading_at_rule::DescriptorDeclaration;
use crate::stylesheets::container_rule::ContainerSizeQuery;
use crate::stylesheets::{Origin, StylesheetInDocument};
use crate::values::computed::{Context, ToComputedValue};
use crate::values::generics::length::LengthPercentageOrAuto;
use crate::values::generics::NonNegative;
use crate::values::specified::{self, NoCalcLength};
use crate::values::specified::{NonNegativeLengthPercentageOrAuto, ViewportPercentageLength};
use app_units::Au;
use cssparser::{
parse_important, AtRuleParser, CowRcStr, DeclarationParser, Parser, QualifiedRuleParser,
RuleBodyItemParser, RuleBodyParser,
};
use euclid::Size2D;
use selectors::parser::SelectorParseErrorKind;
use std::borrow::Cow;
use std::fmt::{self, Write};
use std::iter::Enumerate;
use std::str::Chars;
use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom};
use style_traits::{CssWriter, ParseError, PinchZoomFactor, StyleParseErrorKind, ToCss};
/// Whether parsing and processing of `@viewport` rules is enabled.
#[cfg(feature = "servo")]
pub fn enabled() -> bool {
use servo_config::pref;
pref!(layout.viewport.enabled)
}
/// Whether parsing and processing of `@viewport` rules is enabled.
#[cfg(not(feature = "servo"))]
pub fn enabled() -> bool {
false // Gecko doesn't support @viewport.
}
macro_rules! declare_viewport_descriptor {
( $( $variant_name: expr => $variant: ident($data: ident), )+ ) => {
declare_viewport_descriptor_inner!([] [ $( $variant_name => $variant($data), )+ ] 0);
};
}
macro_rules! declare_viewport_descriptor_inner {
(
[ $( $assigned_variant_name: expr =>
$assigned_variant: ident($assigned_data: ident) = $assigned_discriminant: expr, )* ]
[
$next_variant_name: expr => $next_variant: ident($next_data: ident),
$( $variant_name: expr => $variant: ident($data: ident), )*
]
$next_discriminant: expr
) => {
declare_viewport_descriptor_inner! {
[
$( $assigned_variant_name => $assigned_variant($assigned_data) = $assigned_discriminant, )*
$next_variant_name => $next_variant($next_data) = $next_discriminant,
]
[ $( $variant_name => $variant($data), )* ]
$next_discriminant + 1
}
};
(
[ $( $assigned_variant_name: expr =>
$assigned_variant: ident($assigned_data: ident) = $assigned_discriminant: expr, )* ]
[ ]
$number_of_variants: expr
) => {
#[derive(Clone, Debug, PartialEq, ToShmem)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[allow(missing_docs)]
pub enum ViewportDescriptor {
$(
$assigned_variant($assigned_data),
)+
}
const VIEWPORT_DESCRIPTOR_VARIANTS: usize = $number_of_variants;
impl ViewportDescriptor {
#[allow(missing_docs)]
pub fn discriminant_value(&self) -> usize {
match *self {
$(
ViewportDescriptor::$assigned_variant(..) => $assigned_discriminant,
)*
}
}
}
impl ToCss for ViewportDescriptor {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
match *self {
$(
ViewportDescriptor::$assigned_variant(ref val) => {
dest.write_str($assigned_variant_name)?;
dest.write_str(": ")?;
val.to_css(dest)?;
},
)*
}
dest.write_char(';')
}
}
};
}
declare_viewport_descriptor! {
"min-width" => MinWidth(ViewportLength),
"max-width" => MaxWidth(ViewportLength),
"min-height" => MinHeight(ViewportLength),
"max-height" => MaxHeight(ViewportLength),
"zoom" => Zoom(Zoom),
"min-zoom" => MinZoom(Zoom),
"max-zoom" => MaxZoom(Zoom),
"user-zoom" => UserZoom(UserZoom),
"orientation" => Orientation(Orientation),
}
trait FromMeta: Sized {
fn from_meta(value: &str) -> Option<Self>;
}
/// ViewportLength is a length | percentage | auto | extend-to-zoom
/// See:
/// * http://dev.w3.org/csswg/css-device-adapt/#min-max-width-desc
/// * http://dev.w3.org/csswg/css-device-adapt/#extend-to-zoom
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Clone, Debug, PartialEq, ToCss, ToShmem)]
pub enum ViewportLength {
Specified(NonNegativeLengthPercentageOrAuto),
ExtendToZoom,
}
impl FromMeta for ViewportLength {
fn from_meta(value: &str) -> Option<ViewportLength> {
macro_rules! specified {
($value:expr) => {
ViewportLength::Specified(LengthPercentageOrAuto::LengthPercentage(NonNegative(
specified::LengthPercentage::Length($value),
)))
};
}
Some(match value {
v if v.eq_ignore_ascii_case("device-width") => specified!(
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(100.))
),
v if v.eq_ignore_ascii_case("device-height") => specified!(
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vh(100.))
),
_ => match value.parse::<f32>() {
Ok(n) if n >= 0. => specified!(NoCalcLength::from_px(n.max(1.).min(10000.))),
Ok(_) => return None,
Err(_) => specified!(NoCalcLength::from_px(1.)),
},
})
}
}
impl ViewportLength {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
// we explicitly do not accept 'extend-to-zoom', since it is a UA
// internal value for <META> viewport translation
NonNegativeLengthPercentageOrAuto::parse(context, input).map(ViewportLength::Specified)
}
}
impl FromMeta for Zoom {
fn from_meta(value: &str) -> Option<Zoom> {
Some(match value {
v if v.eq_ignore_ascii_case("yes") => Zoom::Number(1.),
v if v.eq_ignore_ascii_case("no") => Zoom::Number(0.1),
v if v.eq_ignore_ascii_case("device-width") => Zoom::Number(10.),
v if v.eq_ignore_ascii_case("device-height") => Zoom::Number(10.),
_ => match value.parse::<f32>() {
Ok(n) if n >= 0. => Zoom::Number(n.max(0.1).min(10.)),
Ok(_) => return None,
Err(_) => Zoom::Number(0.1),
},
})
}
}
impl FromMeta for UserZoom {
fn from_meta(value: &str) -> Option<UserZoom> {
Some(match value {
v if v.eq_ignore_ascii_case("yes") => UserZoom::Zoom,
v if v.eq_ignore_ascii_case("no") => UserZoom::Fixed,
v if v.eq_ignore_ascii_case("device-width") => UserZoom::Zoom,
v if v.eq_ignore_ascii_case("device-height") => UserZoom::Zoom,
_ => match value.parse::<f32>() {
Ok(n) if n >= 1. || n <= -1. => UserZoom::Zoom,
_ => UserZoom::Fixed,
},
})
}
}
struct ViewportRuleParser<'a, 'b: 'a> {
context: &'a ParserContext<'b>,
}
#[allow(missing_docs)]
pub type ViewportDescriptorDeclaration = DescriptorDeclaration<ViewportDescriptor>;
fn parse_shorthand<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<(ViewportLength, ViewportLength), ParseError<'i>> {
let min = ViewportLength::parse(context, input)?;
match input.try_parse(|i| ViewportLength::parse(context, i)) {
Err(_) => Ok((min.clone(), min)),
Ok(max) => Ok((min, max)),
}
}
type ViewportDeclarations = Vec<ViewportDescriptorDeclaration>;
impl<'a, 'b, 'i> AtRuleParser<'i> for ViewportRuleParser<'a, 'b> {
type Prelude = ();
type AtRule = ViewportDeclarations;
type Error = StyleParseErrorKind<'i>;
}
impl<'a, 'b, 'i> QualifiedRuleParser<'i> for ViewportRuleParser<'a, 'b> {
type Prelude = ();
type QualifiedRule = ViewportDeclarations;
type Error = StyleParseErrorKind<'i>;
}
impl<'a, 'b, 'i> DeclarationParser<'i> for ViewportRuleParser<'a, 'b> {
type Declaration = Vec<ViewportDescriptorDeclaration>;
type Error = StyleParseErrorKind<'i>;
fn parse_value<'t>(
&mut self,
name: CowRcStr<'i>,
input: &mut Parser<'i, 't>,
) -> Result<Vec<ViewportDescriptorDeclaration>, ParseError<'i>> {
macro_rules! declaration {
($declaration:ident($parse:expr)) => {
declaration!($declaration {
value: $parse(input)?,
important: input.try_parse(parse_important).is_ok(),
})
};
($declaration:ident { value: $value:expr, important: $important:expr, }) => {
ViewportDescriptorDeclaration::new(
self.context.stylesheet_origin,
ViewportDescriptor::$declaration($value),
$important,
)
};
}
macro_rules! ok {
($declaration:ident($parse:expr)) => {
Ok(vec![declaration!($declaration($parse))])
};
(shorthand -> [$min:ident, $max:ident]) => {{
let shorthand = parse_shorthand(self.context, input)?;
let important = input.try_parse(parse_important).is_ok();
Ok(vec![
declaration!($min {
value: shorthand.0,
important: important,
}),
declaration!($max {
value: shorthand.1,
important: important,
}),
])
}};
}
match_ignore_ascii_case! { &*name,
"min-width" => ok!(MinWidth(|i| ViewportLength::parse(self.context, i))),
"max-width" => ok!(MaxWidth(|i| ViewportLength::parse(self.context, i))),
"width" => ok!(shorthand -> [MinWidth, MaxWidth]),
"min-height" => ok!(MinHeight(|i| ViewportLength::parse(self.context, i))),
"max-height" => ok!(MaxHeight(|i| ViewportLength::parse(self.context, i))),
"height" => ok!(shorthand -> [MinHeight, MaxHeight]),
"zoom" => ok!(Zoom(Zoom::parse)),
"min-zoom" => ok!(MinZoom(Zoom::parse)),
"max-zoom" => ok!(MaxZoom(Zoom::parse)),
"user-zoom" => ok!(UserZoom(UserZoom::parse)),
"orientation" => ok!(Orientation(Orientation::parse)),
_ => Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))),
}
}
}
impl<'a, 'b, 'i> RuleBodyItemParser<'i, ViewportDeclarations, StyleParseErrorKind<'i>>
for ViewportRuleParser<'a, 'b>
{
fn parse_declarations(&self) -> bool {
true
}
fn parse_qualified(&self) -> bool {
false
}
}
/// A `@viewport` rule.
#[derive(Clone, Debug, PartialEq, ToShmem)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub struct ViewportRule {
/// The declarations contained in this @viewport rule.
pub declarations: Vec<ViewportDescriptorDeclaration>,
}
/// Whitespace as defined by DEVICE-ADAPT § 9.2
// TODO: should we just use whitespace as defined by HTML5?
const WHITESPACE: &'static [char] = &['\t', '\n', '\r', ' '];
/// Separators as defined by DEVICE-ADAPT § 9.2
// need to use \x2c instead of ',' due to test-tidy
const SEPARATOR: &'static [char] = &['\x2c', ';'];
#[inline]
fn is_whitespace_separator_or_equals(c: &char) -> bool {
WHITESPACE.contains(c) || SEPARATOR.contains(c) || *c == '='
}
impl ViewportRule {
/// Parse a single @viewport rule.
///
/// TODO(emilio): This could use the `Parse` trait now.
pub fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let mut parser = ViewportRuleParser { context };
let mut cascade = Cascade::new();
let mut parser = RuleBodyParser::new(input, &mut parser);
while let Some(result) = parser.next() {
match result {
Ok(declarations) => {
for declarations in declarations {
cascade.add(Cow::Owned(declarations))
}
},
Err((error, slice)) => {
let location = error.location;
let error = ContextualParseError::UnsupportedViewportDescriptorDeclaration(
slice, error,
);
context.log_css_error(location, error);
},
}
}
Ok(ViewportRule {
declarations: cascade.finish(),
})
}
}
impl ViewportRule {
#[allow(missing_docs)]
pub fn from_meta(content: &str) -> Option<ViewportRule> {
let mut declarations = vec![None; VIEWPORT_DESCRIPTOR_VARIANTS];
macro_rules! push_descriptor {
($descriptor:ident($value:expr)) => {{
let descriptor = ViewportDescriptor::$descriptor($value);
let discriminant = descriptor.discriminant_value();
declarations[discriminant] = Some(ViewportDescriptorDeclaration::new(
Origin::Author,
descriptor,
false,
));
}};
}
let mut has_width = false;
let mut has_height = false;
let mut has_zoom = false;
let mut iter = content.chars().enumerate();
macro_rules! start_of_name {
($iter:ident) => {
$iter
.by_ref()
.skip_while(|&(_, c)| is_whitespace_separator_or_equals(&c))
.next()
};
}
while let Some((start, _)) = start_of_name!(iter) {
let property = ViewportRule::parse_meta_property(content, &mut iter, start);
if let Some((name, value)) = property {
macro_rules! push {
($descriptor:ident($translate:path)) => {
if let Some(value) = $translate(value) {
push_descriptor!($descriptor(value));
}
};
}
match name {
n if n.eq_ignore_ascii_case("width") => {
if let Some(value) = ViewportLength::from_meta(value) {
push_descriptor!(MinWidth(ViewportLength::ExtendToZoom));
push_descriptor!(MaxWidth(value));
has_width = true;
}
},
n if n.eq_ignore_ascii_case("height") => {
if let Some(value) = ViewportLength::from_meta(value) {
push_descriptor!(MinHeight(ViewportLength::ExtendToZoom));
push_descriptor!(MaxHeight(value));
has_height = true;
}
},
n if n.eq_ignore_ascii_case("initial-scale") => {
if let Some(value) = Zoom::from_meta(value) {
push_descriptor!(Zoom(value));
has_zoom = true;
}
},
n if n.eq_ignore_ascii_case("minimum-scale") => push!(MinZoom(Zoom::from_meta)),
n if n.eq_ignore_ascii_case("maximum-scale") => push!(MaxZoom(Zoom::from_meta)),
n if n.eq_ignore_ascii_case("user-scalable") => {
push!(UserZoom(UserZoom::from_meta))
},
_ => {},
}
}
}
// DEVICE-ADAPT § 9.4 - The 'width' and 'height' properties
// http://dev.w3.org/csswg/css-device-adapt/#width-and-height-properties
if !has_width && has_zoom {
if has_height {
push_descriptor!(MinWidth(ViewportLength::Specified(
LengthPercentageOrAuto::Auto
)));
push_descriptor!(MaxWidth(ViewportLength::Specified(
LengthPercentageOrAuto::Auto
)));
} else {
push_descriptor!(MinWidth(ViewportLength::ExtendToZoom));
push_descriptor!(MaxWidth(ViewportLength::ExtendToZoom));
}
}
let declarations: Vec<_> = declarations.into_iter().filter_map(|entry| entry).collect();
if !declarations.is_empty() {
Some(ViewportRule { declarations })
} else {
None
}
}
fn parse_meta_property<'a>(
content: &'a str,
iter: &mut Enumerate<Chars<'a>>,
start: usize,
) -> Option<(&'a str, &'a str)> {
fn end_of_token(iter: &mut Enumerate<Chars>) -> Option<(usize, char)> {
iter.by_ref()
.skip_while(|&(_, c)| !is_whitespace_separator_or_equals(&c))
.next()
}
fn skip_whitespace(iter: &mut Enumerate<Chars>) -> Option<(usize, char)> {
iter.by_ref()
.skip_while(|&(_, c)| WHITESPACE.contains(&c))
.next()
}
// <name> <whitespace>* '='
let end = match end_of_token(iter) {
Some((end, c)) if WHITESPACE.contains(&c) => match skip_whitespace(iter) {
Some((_, c)) if c == '=' => end,
_ => return None,
},
Some((end, c)) if c == '=' => end,
_ => return None,
};
let name = &content[start..end];
// <whitespace>* <value>
let start = match skip_whitespace(iter) {
Some((start, c)) if !SEPARATOR.contains(&c) => start,
_ => return None,
};
let value = match end_of_token(iter) {
Some((end, _)) => &content[start..end],
_ => &content[start..],
};
Some((name, value))
}
}
impl ToCssWithGuard for ViewportRule {
// Serialization of ViewportRule is not specced.
fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@viewport { ")?;
let mut iter = self.declarations.iter();
iter.next().unwrap().to_css(&mut CssWriter::new(dest))?;
for declaration in iter {
dest.write_char(' ')?;
declaration.to_css(&mut CssWriter::new(dest))?;
}
dest.write_str(" }")
}
}
#[allow(missing_docs)]
pub struct Cascade {
declarations: Vec<Option<(usize, ViewportDescriptorDeclaration)>>,
count_so_far: usize,
}
#[allow(missing_docs)]
impl Cascade {
pub fn new() -> Self {
Cascade {
declarations: vec![None; VIEWPORT_DESCRIPTOR_VARIANTS],
count_so_far: 0,
}
}
pub fn from_stylesheets<'a, I, S>(
stylesheets: I,
guards: &StylesheetGuards,
device: &Device,
) -> Self
where
I: Iterator<Item = (&'a S, Origin)>,
S: StylesheetInDocument + 'static,
{
let mut cascade = Self::new();
for (stylesheet, origin) in stylesheets {
stylesheet.effective_viewport_rules(device, guards.for_origin(origin), |rule| {
for declaration in &rule.declarations {
cascade.add(Cow::Borrowed(declaration))
}
})
}
cascade
}
pub fn add(&mut self, declaration: Cow<ViewportDescriptorDeclaration>) {
let descriptor = declaration.descriptor.discriminant_value();
match self.declarations[descriptor] {
Some((ref mut order_of_appearance, ref mut entry_declaration)) => {
if declaration.higher_or_equal_precendence(entry_declaration) {
*entry_declaration = declaration.into_owned();
*order_of_appearance = self.count_so_far;
}
},
ref mut entry @ None => {
*entry = Some((self.count_so_far, declaration.into_owned()));
},
}
self.count_so_far += 1;
}
pub fn finish(mut self) -> Vec<ViewportDescriptorDeclaration> {
// sort the descriptors by order of appearance
self.declarations
.sort_by_key(|entry| entry.as_ref().map(|&(index, _)| index));
self.declarations
.into_iter()
.filter_map(|entry| entry.map(|(_, decl)| decl))
.collect()
}
}
/// Just a helper trait to be able to implement methods on ViewportConstraints.
pub trait MaybeNew {
/// Create a ViewportConstraints from a viewport size and a `@viewport`
/// rule.
fn maybe_new(
device: &Device,
rule: &ViewportRule,
quirks_mode: QuirksMode,
) -> Option<ViewportConstraints>;
}
impl MaybeNew for ViewportConstraints {
fn maybe_new(
device: &Device,
rule: &ViewportRule,
quirks_mode: QuirksMode,
) -> Option<ViewportConstraints> {
use std::cmp;
if rule.declarations.is_empty() {
return None;
}
let mut min_width = None;
let mut max_width = None;
let mut min_height = None;
let mut max_height = None;
let mut initial_zoom = None;
let mut min_zoom = None;
let mut max_zoom = None;
let mut user_zoom = UserZoom::Zoom;
let mut orientation = Orientation::Auto;
// collapse the list of declarations into descriptor values
for declaration in &rule.declarations {
match declaration.descriptor {
ViewportDescriptor::MinWidth(ref value) => min_width = Some(value),
ViewportDescriptor::MaxWidth(ref value) => max_width = Some(value),
ViewportDescriptor::MinHeight(ref value) => min_height = Some(value),
ViewportDescriptor::MaxHeight(ref value) => max_height = Some(value),
ViewportDescriptor::Zoom(value) => initial_zoom = value.to_f32(),
ViewportDescriptor::MinZoom(value) => min_zoom = value.to_f32(),
ViewportDescriptor::MaxZoom(value) => max_zoom = value.to_f32(),
ViewportDescriptor::UserZoom(value) => user_zoom = value,
ViewportDescriptor::Orientation(value) => orientation = value,
}
}
// TODO: return `None` if all descriptors are either absent or initial value
macro_rules! choose {
($op:ident, $opta:expr, $optb:expr) => {
match ($opta, $optb) {
(None, None) => None,
(a, None) => a,
(None, b) => b,
(Some(a), Some(b)) => Some(a.$op(b)),
}
};
}
macro_rules! min {
($opta:expr, $optb:expr) => {
choose!(min, $opta, $optb)
};
}
macro_rules! max {
($opta:expr, $optb:expr) => {
choose!(max, $opta, $optb)
};
}
// DEVICE-ADAPT § 6.2.1 Resolve min-zoom and max-zoom values
if min_zoom.is_some() && max_zoom.is_some() {
max_zoom = Some(min_zoom.unwrap().max(max_zoom.unwrap()))
}
// DEVICE-ADAPT § 6.2.2 Constrain zoom value to the [min-zoom, max-zoom] range
if initial_zoom.is_some() {
initial_zoom = max!(min_zoom, min!(max_zoom, initial_zoom));
}
// DEVICE-ADAPT § 6.2.3 Resolve non-auto lengths to pixel lengths
let initial_viewport = device.au_viewport_size();
let mut conditions = RuleCacheConditions::default();
let context = Context::new(
// Note: DEVICE-ADAPT § 5. states that relative length values are
// resolved against initial values
StyleBuilder::for_inheritance(device, None, None),
quirks_mode,
&mut conditions,
ContainerSizeQuery::none(),
);
// DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom'
let extend_width;
let extend_height;
if let Some(extend_zoom) = max!(initial_zoom, max_zoom) {
let scale_factor = 1. / extend_zoom;
extend_width = Some(initial_viewport.width.scale_by(scale_factor));
extend_height = Some(initial_viewport.height.scale_by(scale_factor));
} else {
extend_width = None;
extend_height = None;
}
macro_rules! to_pixel_length {
($value:ident, $dimension:ident, $extend_to:ident => $auto_extend_to:expr) => {
if let Some($value) = $value {
match *$value {
ViewportLength::Specified(ref length) => match *length {
LengthPercentageOrAuto::Auto => None,
LengthPercentageOrAuto::LengthPercentage(ref lop) => Some(
lop.to_computed_value(&context)
.to_used_value(initial_viewport.$dimension),
),
},
ViewportLength::ExtendToZoom => {
// $extend_to will be 'None' if 'extend-to-zoom' is 'auto'
match ($extend_to, $auto_extend_to) {
(None, None) => None,
(a, None) => a,
(None, b) => b,
(a, b) => cmp::max(a, b),
}
},
}
} else {
None
}
};
}
// DEVICE-ADAPT § 9.3 states that max-descriptors need to be resolved
// before min-descriptors.
// http://dev.w3.org/csswg/css-device-adapt/#resolve-extend-to-zoom
let max_width = to_pixel_length!(max_width, width, extend_width => None);
let max_height = to_pixel_length!(max_height, height, extend_height => None);
let min_width = to_pixel_length!(min_width, width, extend_width => max_width);
let min_height = to_pixel_length!(min_height, height, extend_height => max_height);
// DEVICE-ADAPT § 6.2.4 Resolve initial width and height from min/max descriptors
macro_rules! resolve {
($min:ident, $max:ident, $initial:expr) => {
if $min.is_some() || $max.is_some() {
let max = match $max {
Some(max) => cmp::min(max, $initial),
None => $initial,
};
Some(match $min {
Some(min) => cmp::max(min, max),
None => max,
})
} else {
None
}
};
}
let width = resolve!(min_width, max_width, initial_viewport.width);
let height = resolve!(min_height, max_height, initial_viewport.height);
// DEVICE-ADAPT § 6.2.5 Resolve width value
let width = if width.is_none() && height.is_none() {
Some(initial_viewport.width)
} else {
width
};
let width = width.unwrap_or_else(|| match initial_viewport.height {
Au(0) => initial_viewport.width,
initial_height => {
let ratio = initial_viewport.width.to_f32_px() / initial_height.to_f32_px();
Au::from_f32_px(height.unwrap().to_f32_px() * ratio)
},
});
// DEVICE-ADAPT § 6.2.6 Resolve height value
let height = height.unwrap_or_else(|| match initial_viewport.width {
Au(0) => initial_viewport.height,
initial_width => {
let ratio = initial_viewport.height.to_f32_px() / initial_width.to_f32_px();
Au::from_f32_px(width.to_f32_px() * ratio)
},
});
Some(ViewportConstraints {
size: Size2D::new(width.to_f32_px(), height.to_f32_px()),
// TODO: compute a zoom factor for 'auto' as suggested by DEVICE-ADAPT § 10.
initial_zoom: PinchZoomFactor::new(initial_zoom.unwrap_or(1.)),
min_zoom: min_zoom.map(PinchZoomFactor::new),
max_zoom: max_zoom.map(PinchZoomFactor::new),
user_zoom,
orientation,
})
}
}

Просмотреть файл

@ -31,7 +31,6 @@ use crate::stylesheets::container_rule::ContainerCondition;
use crate::stylesheets::import_rule::ImportLayer; use crate::stylesheets::import_rule::ImportLayer;
use crate::stylesheets::keyframes_rule::KeyframesAnimation; use crate::stylesheets::keyframes_rule::KeyframesAnimation;
use crate::stylesheets::layer_rule::{LayerName, LayerOrder}; use crate::stylesheets::layer_rule::{LayerName, LayerOrder};
use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::stylesheets::{ use crate::stylesheets::{
CounterStyleRule, FontFaceRule, FontFeatureValuesRule, FontPaletteValuesRule, PageRule, CounterStyleRule, FontFaceRule, FontFeatureValuesRule, FontPaletteValuesRule, PageRule,
@ -64,7 +63,6 @@ use std::cmp::Ordering;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::sync::Mutex; use std::sync::Mutex;
use std::{mem, ops}; use std::{mem, ops};
use style_traits::viewport::ViewportConstraints;
/// The type of the stylesheets that the stylist contains. /// The type of the stylesheets that the stylist contains.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
@ -503,9 +501,6 @@ pub struct Stylist {
/// `set_device`. /// `set_device`.
device: Device, device: Device,
/// Viewport constraints based on the current device.
viewport_constraints: Option<ViewportConstraints>,
/// The list of stylesheets. /// The list of stylesheets.
stylesheets: StylistStylesheetSet, stylesheets: StylistStylesheetSet,
@ -609,7 +604,6 @@ impl Stylist {
#[inline] #[inline]
pub fn new(device: Device, quirks_mode: QuirksMode) -> Self { pub fn new(device: Device, quirks_mode: QuirksMode) -> Self {
Self { Self {
viewport_constraints: None,
device, device,
quirks_mode, quirks_mode,
stylesheets: StylistStylesheetSet::new(), stylesheets: StylistStylesheetSet::new(),
@ -733,37 +727,6 @@ impl Stylist {
self.num_rebuilds += 1; self.num_rebuilds += 1;
// Update viewport_constraints regardless of which origins'
// `CascadeData` we're updating.
self.viewport_constraints = None;
if viewport_rule::enabled() {
// TODO(emilio): This doesn't look so efficient.
//
// Presumably when we properly implement this we can at least have a
// bit on the stylesheet that says whether it contains viewport
// rules to skip it entirely?
//
// Processing it with the rest of rules seems tricky since it
// overrides the viewport size which may change the evaluation of
// media queries (or may not? how are viewport units in media
// queries defined?)
let cascaded_rule = ViewportRule {
declarations: viewport_rule::Cascade::from_stylesheets(
self.stylesheets.iter(),
guards,
&self.device,
)
.finish(),
};
self.viewport_constraints =
ViewportConstraints::maybe_new(&self.device, &cascaded_rule, self.quirks_mode);
if let Some(ref constraints) = self.viewport_constraints {
self.device.account_for_viewport_rule(constraints);
}
}
let flusher = self.stylesheets.flush(document_element, snapshots); let flusher = self.stylesheets.flush(document_element, snapshots);
let had_invalidations = flusher.had_invalidations(); let had_invalidations = flusher.had_invalidations();
@ -1229,29 +1192,7 @@ impl Stylist {
/// ///
/// Also, the device that arrives here may need to take the viewport rules /// Also, the device that arrives here may need to take the viewport rules
/// into account. /// into account.
pub fn set_device(&mut self, mut device: Device, guards: &StylesheetGuards) -> OriginSet { pub fn set_device(&mut self, device: Device, guards: &StylesheetGuards) -> OriginSet {
if viewport_rule::enabled() {
let cascaded_rule = {
let stylesheets = self.stylesheets.iter();
ViewportRule {
declarations: viewport_rule::Cascade::from_stylesheets(
stylesheets,
guards,
&device,
)
.finish(),
}
};
self.viewport_constraints =
ViewportConstraints::maybe_new(&device, &cascaded_rule, self.quirks_mode);
if let Some(ref constraints) = self.viewport_constraints {
device.account_for_viewport_rule(constraints);
}
}
self.device = device; self.device = device;
self.media_features_change_changed_style(guards, &self.device) self.media_features_change_changed_style(guards, &self.device)
} }
@ -1292,12 +1233,6 @@ impl Stylist {
origins origins
} }
/// Returns the viewport constraints that apply to this document because of
/// a @viewport rule.
pub fn viewport_constraints(&self) -> Option<&ViewportConstraints> {
self.viewport_constraints.as_ref()
}
/// Returns the Quirks Mode of the document. /// Returns the Quirks Mode of the document.
pub fn quirks_mode(&self) -> QuirksMode { pub fn quirks_mode(&self) -> QuirksMode {
self.quirks_mode self.quirks_mode
@ -2836,8 +2771,6 @@ impl CascadeData {
self.extra_data self.extra_data
.add_page(guard, rule, containing_rule_state.layer_id)?; .add_page(guard, rule, containing_rule_state.layer_id)?;
}, },
// TODO: Handle CssRule::Property
CssRule::Viewport(..) => {},
_ => { _ => {
handled = false; handled = false;
}, },
@ -3080,7 +3013,6 @@ impl CascadeData {
CssRule::Keyframes(..) | CssRule::Keyframes(..) |
CssRule::Page(..) | CssRule::Page(..) |
CssRule::Property(..) | CssRule::Property(..) |
CssRule::Viewport(..) |
CssRule::Document(..) | CssRule::Document(..) |
CssRule::LayerBlock(..) | CssRule::LayerBlock(..) |
CssRule::LayerStatement(..) | CssRule::LayerStatement(..) |

Просмотреть файл

@ -13,7 +13,6 @@
extern crate app_units; extern crate app_units;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
#[macro_use]
extern crate cssparser; extern crate cssparser;
extern crate euclid; extern crate euclid;
#[macro_use] #[macro_use]
@ -90,8 +89,6 @@ pub mod dom;
pub mod specified_value_info; pub mod specified_value_info;
#[macro_use] #[macro_use]
pub mod values; pub mod values;
#[macro_use]
pub mod viewport;
pub mod owned_slice; pub mod owned_slice;
pub mod owned_str; pub mod owned_str;

Просмотреть файл

@ -502,61 +502,6 @@ impl_to_css_for_predefined_type!(u32);
impl_to_css_for_predefined_type!(::cssparser::Token<'a>); impl_to_css_for_predefined_type!(::cssparser::Token<'a>);
impl_to_css_for_predefined_type!(::cssparser::UnicodeRange); impl_to_css_for_predefined_type!(::cssparser::UnicodeRange);
/// Define an enum type with unit variants that each correspond to a CSS keyword.
macro_rules! define_css_keyword_enum {
(pub enum $name:ident { $($variant:ident = $css:expr,)+ }) => {
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)]
pub enum $name {
$($variant),+
}
impl $name {
/// Parse this property from a CSS input stream.
pub fn parse<'i, 't>(input: &mut ::cssparser::Parser<'i, 't>)
-> Result<$name, $crate::ParseError<'i>> {
use cssparser::Token;
let location = input.current_source_location();
match *input.next()? {
Token::Ident(ref ident) => {
Self::from_ident(ident).map_err(|()| {
location.new_unexpected_token_error(
Token::Ident(ident.clone()),
)
})
}
ref token => {
Err(location.new_unexpected_token_error(token.clone()))
}
}
}
/// Parse this property from an already-tokenized identifier.
pub fn from_ident(ident: &str) -> Result<$name, ()> {
match_ignore_ascii_case! { ident,
$($css => Ok($name::$variant),)+
_ => Err(())
}
}
}
impl $crate::ToCss for $name {
fn to_css<W>(
&self,
dest: &mut $crate::CssWriter<W>,
) -> ::std::fmt::Result
where
W: ::std::fmt::Write,
{
match *self {
$( $name::$variant => ::std::fmt::Write::write_str(dest, $css) ),+
}
}
}
};
}
/// Helper types for the handling of specified values. /// Helper types for the handling of specified values.
pub mod specified { pub mod specified {
use crate::ParsingMode; use crate::ParsingMode;

Просмотреть файл

@ -1,148 +0,0 @@
/* 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 https://mozilla.org/MPL/2.0/. */
//! Helper types for the `@viewport` rule.
use crate::{CSSPixel, CssWriter, ParseError, PinchZoomFactor, ToCss};
use cssparser::Parser;
use euclid::Size2D;
use std::fmt::{self, Write};
define_css_keyword_enum! {
pub enum UserZoom {
Zoom = "zoom",
Fixed = "fixed",
}
}
define_css_keyword_enum! {
pub enum Orientation {
Auto = "auto",
Portrait = "portrait",
Landscape = "landscape",
}
}
/// A set of viewport descriptors:
///
/// <https://drafts.csswg.org/css-device-adapt/#viewport-desc>
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, MallocSizeOf))]
pub struct ViewportConstraints {
/// Width and height:
/// * https://drafts.csswg.org/css-device-adapt/#width-desc
/// * https://drafts.csswg.org/css-device-adapt/#height-desc
pub size: Size2D<f32, CSSPixel>,
/// <https://drafts.csswg.org/css-device-adapt/#zoom-desc>
pub initial_zoom: PinchZoomFactor,
/// <https://drafts.csswg.org/css-device-adapt/#min-max-width-desc>
pub min_zoom: Option<PinchZoomFactor>,
/// <https://drafts.csswg.org/css-device-adapt/#min-max-width-desc>
pub max_zoom: Option<PinchZoomFactor>,
/// <https://drafts.csswg.org/css-device-adapt/#user-zoom-desc>
pub user_zoom: UserZoom,
/// <https://drafts.csswg.org/css-device-adapt/#orientation-desc>
pub orientation: Orientation,
}
impl ToCss for ViewportConstraints {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
dest.write_str("@viewport { width: ")?;
self.size.width.to_css(dest)?;
dest.write_str("px; height: ")?;
self.size.height.to_css(dest)?;
dest.write_str("px; zoom: ")?;
self.initial_zoom.get().to_css(dest)?;
if let Some(min_zoom) = self.min_zoom {
dest.write_str("; min-zoom: ")?;
min_zoom.get().to_css(dest)?;
}
if let Some(max_zoom) = self.max_zoom {
dest.write_str("; max-zoom: ")?;
max_zoom.get().to_css(dest)?;
}
dest.write_str("; user-zoom: ")?;
self.user_zoom.to_css(dest)?;
dest.write_str("; orientation: ")?;
self.orientation.to_css(dest)?;
dest.write_str("; }")
}
}
/// <https://drafts.csswg.org/css-device-adapt/#descdef-viewport-zoom>
#[derive(Clone, Copy, Debug, PartialEq, ToShmem)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub enum Zoom {
/// A number value.
Number(f32),
/// A percentage value.
Percentage(f32),
/// The `auto` keyword.
Auto,
}
impl ToCss for Zoom {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: fmt::Write,
{
match *self {
Zoom::Number(number) => number.to_css(dest),
Zoom::Auto => dest.write_str("auto"),
Zoom::Percentage(percentage) => {
(percentage * 100.).to_css(dest)?;
dest.write_char('%')
},
}
}
}
impl Zoom {
/// Parse a zoom value per:
///
/// <https://drafts.csswg.org/css-device-adapt/#descdef-viewport-zoom>
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Zoom, ParseError<'i>> {
use crate::values::specified::AllowedNumericType::NonNegative;
use crate::ParsingMode;
use cssparser::Token;
let location = input.current_source_location();
match *input.next()? {
// TODO: This parse() method should take ParserContext as an
// argument, and pass ParsingMode owned by the ParserContext to
// is_ok() instead of using ParsingMode::DEFAULT directly.
// In order to do so, we might want to move these stuff into style::stylesheets::viewport_rule.
Token::Percentage { unit_value, .. }
if NonNegative.is_ok(ParsingMode::DEFAULT, unit_value) =>
{
Ok(Zoom::Percentage(unit_value))
},
Token::Number { value, .. } if NonNegative.is_ok(ParsingMode::DEFAULT, value) => {
Ok(Zoom::Number(value))
},
Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => Ok(Zoom::Auto),
ref t => Err(location.new_unexpected_token_error(t.clone())),
}
}
/// Get this zoom value as a float value. Returns `None` if the value is the
/// `auto` keyword.
#[inline]
pub fn to_f32(&self) -> Option<f32> {
match *self {
Zoom::Number(number) => Some(number as f32),
Zoom::Percentage(percentage) => Some(percentage as f32),
Zoom::Auto => None,
}
}
}

Просмотреть файл

@ -33,4 +33,3 @@ mod specified_values;
mod str; mod str;
mod stylesheets; mod stylesheets;
mod stylist; mod stylist;
mod viewport;

Просмотреть файл

@ -1,383 +0,0 @@
/* 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 https://mozilla.org/MPL/2.0/. */
use cssparser::{Parser, ParserInput};
use euclid::Scale;
use euclid::Size2D;
use servo_arc::Arc;
use servo_config::prefs::{PREFS, PrefValue};
use servo_url::ServoUrl;
use style::context::QuirksMode;
use style::media_queries::{Device, MediaList, MediaType};
use style::parser::ParserContext;
use style::shared_lock::{SharedRwLock, StylesheetGuards};
use style::stylesheets::{CssRuleType, Stylesheet, StylesheetInDocument, Origin};
use style::stylesheets::viewport_rule::*;
use style::values::specified::LengthPercentageOrAuto::{self, Auto};
use style::values::specified::NoCalcLength::{self, ViewportPercentage};
use style::values::specified::ViewportPercentageLength::Vw;
use style_traits::{ParsingMode, PinchZoomFactor};
use style_traits::viewport::*;
macro_rules! stylesheet {
($css:expr, $origin:ident) => {
stylesheet!($css, $origin, SharedRwLock::new())
};
($css:expr, $origin:ident, $shared_lock:expr) => {
Arc::new(Stylesheet::from_str(
$css,
ServoUrl::parse("http://localhost").unwrap(),
Origin::$origin,
Arc::new($shared_lock.wrap(MediaList::empty())),
$shared_lock,
None,
None,
QuirksMode::NoQuirks,
0
))
}
}
fn test_viewport_rule<F>(css: &str,
device: &Device,
callback: F)
where F: Fn(&Vec<ViewportDescriptorDeclaration>, &str)
{
PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true));
let stylesheet = stylesheet!(css, Author);
let mut rule_count = 0;
stylesheet.effective_viewport_rules(&device, &stylesheet.shared_lock.read(), |rule| {
rule_count += 1;
callback(&rule.declarations, css);
});
assert!(rule_count > 0);
}
fn test_meta_viewport<F>(meta: &str, callback: F)
where F: Fn(&Vec<ViewportDescriptorDeclaration>, &str)
{
if let Some(mut rule) = ViewportRule::from_meta(meta) {
// from_meta uses a hash-map to collect the declarations, so we need to
// sort them in a stable order for the tests
rule.declarations.sort_by(|a, b| {
let a = a.descriptor.discriminant_value();
let b = b.descriptor.discriminant_value();
a.cmp(&b)
});
callback(&rule.declarations, meta);
} else {
panic!("no @viewport rule for {}", meta);
}
}
macro_rules! assert_decl_len {
($declarations:ident == 1) => {
assert_eq!($declarations.len(), 1,
"expected 1 declaration; have {}: {:?})",
$declarations.len(), $declarations)
};
($declarations:ident == $len:expr) => {
assert_eq!($declarations.len(), $len,
"expected {} declarations; have {}: {:?})",
$len, $declarations.len(), $declarations)
}
}
macro_rules! viewport_length {
($value:expr, px) => {
ViewportLength::Specified(LengthPercentageOrAuto::Length(NoCalcLength::from_px($value)))
};
($value:expr, vw) => {
ViewportLength::Specified(LengthPercentageOrAuto::Length(ViewportPercentage(Vw($value))))
}
}
#[test]
fn empty_viewport_rule() {
let device = Device::new(MediaType::screen(), Size2D::new(800., 600.), Scale::new(1.0));
test_viewport_rule("@viewport {}", &device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 0);
});
}
macro_rules! assert_decl_eq {
($d:expr, $origin:ident, $expected:ident: $value:expr) => {{
assert_eq!($d.origin, Origin::$origin);
assert_eq!($d.descriptor, ViewportDescriptor::$expected($value));
assert_eq!($d.important, false, "descriptor should not be !important");
}};
($d:expr, $origin:ident, $expected:ident: $value:expr, !important) => {{
assert_eq!($d.origin, Origin::$origin);
assert_eq!($d.descriptor, ViewportDescriptor::$expected($value));
assert_eq!($d.important, true, "descriptor should be !important");
}};
}
#[test]
fn simple_viewport_rules() {
let device = Device::new(MediaType::screen(), Size2D::new(800., 600.), Scale::new(1.0));
test_viewport_rule("@viewport { width: auto; height: auto;\
zoom: auto; min-zoom: 0; max-zoom: 200%;\
user-zoom: zoom; orientation: auto; }",
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 9);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto));
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto));
assert_decl_eq!(&declarations[2], Author, MinHeight: ViewportLength::Specified(Auto));
assert_decl_eq!(&declarations[3], Author, MaxHeight: ViewportLength::Specified(Auto));
assert_decl_eq!(&declarations[4], Author, Zoom: Zoom::Auto);
assert_decl_eq!(&declarations[5], Author, MinZoom: Zoom::Number(0.));
assert_decl_eq!(&declarations[6], Author, MaxZoom: Zoom::Percentage(2.));
assert_decl_eq!(&declarations[7], Author, UserZoom: UserZoom::Zoom);
assert_decl_eq!(&declarations[8], Author, Orientation: Orientation::Auto);
});
test_viewport_rule("@viewport { min-width: 200px; max-width: auto;\
min-height: 200px; max-height: auto; }",
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 4);
assert_decl_eq!(&declarations[0], Author, MinWidth: viewport_length!(200., px));
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto));
assert_decl_eq!(&declarations[2], Author, MinHeight: viewport_length!(200., px));
assert_decl_eq!(&declarations[3], Author, MaxHeight: ViewportLength::Specified(Auto));
});
}
#[test]
fn simple_meta_viewport_contents() {
test_meta_viewport("width=500, height=600", |declarations, meta| {
println!("{}", meta);
assert_decl_len!(declarations == 4);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::ExtendToZoom);
assert_decl_eq!(&declarations[1], Author, MaxWidth: viewport_length!(500., px));
assert_decl_eq!(&declarations[2], Author, MinHeight: ViewportLength::ExtendToZoom);
assert_decl_eq!(&declarations[3], Author, MaxHeight: viewport_length!(600., px));
});
test_meta_viewport("initial-scale=1.0", |declarations, meta| {
println!("{}", meta);
assert_decl_len!(declarations == 3);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::ExtendToZoom);
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::ExtendToZoom);
assert_decl_eq!(&declarations[2], Author, Zoom: Zoom::Number(1.));
});
test_meta_viewport("initial-scale=2.0, height=device-width", |declarations, meta| {
println!("{}", meta);
assert_decl_len!(declarations == 5);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto));
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto));
assert_decl_eq!(&declarations[2], Author, MinHeight: ViewportLength::ExtendToZoom);
assert_decl_eq!(&declarations[3], Author, MaxHeight: viewport_length!(100., vw));
assert_decl_eq!(&declarations[4], Author, Zoom: Zoom::Number(2.));
});
test_meta_viewport("width=480, initial-scale=2.0, user-scalable=1", |declarations, meta| {
println!("{}", meta);
assert_decl_len!(declarations == 4);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::ExtendToZoom);
assert_decl_eq!(&declarations[1], Author, MaxWidth: viewport_length!(480., px));
assert_decl_eq!(&declarations[2], Author, Zoom: Zoom::Number(2.));
assert_decl_eq!(&declarations[3], Author, UserZoom: UserZoom::Zoom);
});
}
#[test]
fn cascading_within_viewport_rule() {
let device = Device::new(MediaType::screen(), Size2D::new(800., 600.), Scale::new(1.0));
// normal order of appearance
test_viewport_rule("@viewport { min-width: 200px; min-width: auto; }",
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 1);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto));
});
// !important order of appearance
test_viewport_rule("@viewport { min-width: 200px !important; min-width: auto !important; }",
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 1);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto), !important);
});
// !important vs normal
test_viewport_rule("@viewport { min-width: auto !important; min-width: 200px; }",
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 1);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto), !important);
});
// normal longhands vs normal shorthand
test_viewport_rule("@viewport { min-width: 200px; max-width: 200px; width: auto; }",
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 2);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto));
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto));
});
// normal shorthand vs normal longhands
test_viewport_rule("@viewport { width: 200px; min-width: auto; max-width: auto; }",
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 2);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto));
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto));
});
// one !important longhand vs normal shorthand
test_viewport_rule("@viewport { min-width: auto !important; width: 200px; }",
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 2);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto), !important);
assert_decl_eq!(&declarations[1], Author, MaxWidth: viewport_length!(200., px));
});
// both !important longhands vs normal shorthand
test_viewport_rule("@viewport { min-width: auto !important; max-width: auto !important; width: 200px; }",
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 2);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto), !important);
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto), !important);
});
}
#[test]
fn multiple_stylesheets_cascading() {
PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true));
let device = Device::new(MediaType::screen(), Size2D::new(800., 600.), Scale::new(1.0));
let shared_lock = SharedRwLock::new();
let stylesheets = vec![
stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }",
UserAgent,
shared_lock.clone()),
stylesheet!("@viewport { min-width: 200px; min-height: 200px; }",
User, shared_lock.clone()),
stylesheet!("@viewport { min-width: 300px; }",
Author, shared_lock.clone())
];
let declarations = Cascade::from_stylesheets(
stylesheets.iter().map(|s| (&**s, Origin::Author)),
&StylesheetGuards::same(&shared_lock.read()),
&device,
).finish();
assert_decl_len!(declarations == 3);
assert_decl_eq!(&declarations[0], UserAgent, Zoom: Zoom::Number(1.));
assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px));
assert_decl_eq!(&declarations[2], Author, MinWidth: viewport_length!(300., px));
let stylesheets = vec![
stylesheet!("@viewport { min-width: 100px !important; }",
UserAgent, shared_lock.clone()),
stylesheet!("@viewport { min-width: 200px !important; min-height: 200px !important; }",
User, shared_lock.clone()),
stylesheet!("@viewport { min-width: 300px !important; min-height: 300px !important; zoom: 3 !important; }",
Author, shared_lock.clone())
];
let declarations = Cascade::from_stylesheets(
stylesheets.iter().map(|s| (&**s, Origin::Author)),
&StylesheetGuards::same(&shared_lock.read()),
&device,
).finish();
assert_decl_len!(declarations == 3);
assert_decl_eq!(&declarations[0], UserAgent, MinWidth: viewport_length!(100., px), !important);
assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px), !important);
assert_decl_eq!(&declarations[2], Author, Zoom: Zoom::Number(3.), !important);
}
#[test]
fn constrain_viewport() {
let url = ServoUrl::parse("http://localhost").unwrap();
let context = ParserContext::new(
Origin::Author,
&url,
Some(CssRuleType::Viewport),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
macro_rules! from_css {
($css:expr) => {
&ViewportRule::parse(&context, &mut Parser::new(&mut $css)).unwrap()
}
}
let initial_viewport = Size2D::new(800., 600.);
let device = Device::new(MediaType::screen(), initial_viewport, Scale::new(1.0));
let mut input = ParserInput::new("");
assert_eq!(ViewportConstraints::maybe_new(&device, from_css!(input), QuirksMode::NoQuirks), None);
let mut input = ParserInput::new("width: 320px auto");
assert_eq!(ViewportConstraints::maybe_new(&device, from_css!(input), QuirksMode::NoQuirks),
Some(ViewportConstraints {
size: initial_viewport,
initial_zoom: PinchZoomFactor::new(1.),
min_zoom: None,
max_zoom: None,
user_zoom: UserZoom::Zoom,
orientation: Orientation::Auto
}));
let mut input = ParserInput::new("width: 320px auto");
assert_eq!(ViewportConstraints::maybe_new(&device, from_css!(input), QuirksMode::NoQuirks),
Some(ViewportConstraints {
size: initial_viewport,
initial_zoom: PinchZoomFactor::new(1.),
min_zoom: None,
max_zoom: None,
user_zoom: UserZoom::Zoom,
orientation: Orientation::Auto
}));
let mut input = ParserInput::new("width: 800px; height: 600px;\
zoom: 1;\
user-zoom: zoom;\
orientation: auto;");
assert_eq!(ViewportConstraints::maybe_new(&device,
from_css!(input),
QuirksMode::NoQuirks),
Some(ViewportConstraints {
size: initial_viewport,
initial_zoom: PinchZoomFactor::new(1.),
min_zoom: None,
max_zoom: None,
user_zoom: UserZoom::Zoom,
orientation: Orientation::Auto
}));
let initial_viewport = Size2D::new(200., 150.);
let device = Device::new(MediaType::screen(), initial_viewport, Scale::new(1.0));
let mut input = ParserInput::new("width: 320px auto");
assert_eq!(ViewportConstraints::maybe_new(&device, from_css!(input), QuirksMode::NoQuirks),
Some(ViewportConstraints {
size: Size2D::new(320., 240.),
initial_zoom: PinchZoomFactor::new(1.),
min_zoom: None,
max_zoom: None,
user_zoom: UserZoom::Zoom,
orientation: Orientation::Auto
}));
}