зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
2e06f92ba0
Коммит
20cac1714b
|
@ -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
|
|
||||||
}));
|
|
||||||
}
|
|
Загрузка…
Ссылка в новой задаче