mirror of
https://github.com/servo/servo.git
synced 2025-06-22 08:08:59 +01:00
Auto merge of #6185 - luniv:viewport-meta, r=mbrubeck
Implement <meta name=viewport> handling Translate <meta name=viewport> as according to [CSS Device Adaption § 9](http://dev.w3.org/csswg/css-device-adapt/#viewport-meta) Note: as the PR currently stands, handling `<meta name=viewport>` elements always occurs. This is probably not desired for some contexts (e.g. desktop), but I'm unsure of how to conditionally handle elements based on that. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6185) <!-- Reviewable:end -->
This commit is contained in:
commit
a7743052ca
9 changed files with 508 additions and 62 deletions
|
@ -78,8 +78,9 @@ use style::media_queries::{Device, MediaQueryList, MediaType};
|
||||||
use style::properties::longhands::{display, position};
|
use style::properties::longhands::{display, position};
|
||||||
use style::properties::style_structs;
|
use style::properties::style_structs;
|
||||||
use style::selector_matching::Stylist;
|
use style::selector_matching::Stylist;
|
||||||
use style::stylesheets::{CSSRuleIteratorExt, Origin, Stylesheet};
|
use style::stylesheets::{CSSRule, CSSRuleIteratorExt, Origin, Stylesheet};
|
||||||
use style::values::AuExtensionMethods;
|
use style::values::AuExtensionMethods;
|
||||||
|
use style::viewport::ViewportRule;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::geometry::{MAX_RECT, ZERO_POINT};
|
use util::geometry::{MAX_RECT, ZERO_POINT};
|
||||||
use util::ipc::OptionalIpcSender;
|
use util::ipc::OptionalIpcSender;
|
||||||
|
@ -618,6 +619,9 @@ impl LayoutTask {
|
||||||
possibly_locked_rw_data)
|
possibly_locked_rw_data)
|
||||||
}
|
}
|
||||||
Msg::SetQuirksMode => self.handle_set_quirks_mode(possibly_locked_rw_data),
|
Msg::SetQuirksMode => self.handle_set_quirks_mode(possibly_locked_rw_data),
|
||||||
|
Msg::AddMetaViewport(translated_rule) => {
|
||||||
|
self.handle_add_meta_viewport(translated_rule, possibly_locked_rw_data)
|
||||||
|
}
|
||||||
Msg::GetRPC(response_chan) => {
|
Msg::GetRPC(response_chan) => {
|
||||||
response_chan.send(box LayoutRPCImpl(self.rw_data.clone()) as
|
response_chan.send(box LayoutRPCImpl(self.rw_data.clone()) as
|
||||||
Box<LayoutRPC + Send>).unwrap();
|
Box<LayoutRPC + Send>).unwrap();
|
||||||
|
@ -823,6 +827,19 @@ impl LayoutTask {
|
||||||
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
|
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_add_meta_viewport<'a>(&'a self,
|
||||||
|
translated_rule: ViewportRule,
|
||||||
|
possibly_locked_rw_data:
|
||||||
|
&mut Option<MutexGuard<'a, LayoutTaskData>>)
|
||||||
|
{
|
||||||
|
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
||||||
|
rw_data.stylist.add_stylesheet(Stylesheet {
|
||||||
|
rules: vec![CSSRule::Viewport(translated_rule)],
|
||||||
|
origin: Origin::Author
|
||||||
|
});
|
||||||
|
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets quirks mode for the document, causing the quirks mode stylesheet to be loaded.
|
/// Sets quirks mode for the document, causing the quirks mode stylesheet to be loaded.
|
||||||
fn handle_set_quirks_mode<'a>(&'a self,
|
fn handle_set_quirks_mode<'a>(&'a self,
|
||||||
possibly_locked_rw_data:
|
possibly_locked_rw_data:
|
||||||
|
@ -1657,4 +1674,3 @@ fn get_root_flow_background_color(flow: &mut Flow) -> AzColor {
|
||||||
.resolve_color(kid_block_flow.fragment.style.get_background().background_color)
|
.resolve_color(kid_block_flow.fragment.style.get_background().background_color)
|
||||||
.to_gfx_color()
|
.to_gfx_color()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,18 @@
|
||||||
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding;
|
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding;
|
||||||
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding::HTMLMetaElementMethods;
|
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding::HTMLMetaElementMethods;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLMetaElementDerived;
|
use dom::bindings::codegen::InheritTypes::HTMLMetaElementDerived;
|
||||||
use dom::bindings::js::Root;
|
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast};
|
||||||
|
use dom::bindings::js::{Root, RootedReference};
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::ElementTypeId;
|
use dom::element::ElementTypeId;
|
||||||
use dom::eventtarget::{EventTarget, EventTargetTypeId};
|
use dom::eventtarget::{EventTarget, EventTargetTypeId};
|
||||||
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
|
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
|
||||||
use dom::node::{Node, NodeTypeId};
|
use dom::node::{Node, NodeTypeId, window_from_node};
|
||||||
use util::str::DOMString;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
use layout_interface::{LayoutChan, Msg};
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
|
use style::viewport::ViewportRule;
|
||||||
|
use util::str::{DOMString, HTML_SPACE_CHARACTERS};
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct HTMLMetaElement {
|
pub struct HTMLMetaElement {
|
||||||
|
@ -42,6 +47,35 @@ impl HTMLMetaElement {
|
||||||
let element = HTMLMetaElement::new_inherited(localName, prefix, document);
|
let element = HTMLMetaElement::new_inherited(localName, prefix, document);
|
||||||
Node::reflect_node(box element, document, HTMLMetaElementBinding::Wrap)
|
Node::reflect_node(box element, document, HTMLMetaElementBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_attributes(&self) {
|
||||||
|
let element = ElementCast::from_ref(self);
|
||||||
|
if let Some(name) = element.get_attribute(&ns!(""), &atom!("name")).r() {
|
||||||
|
let name = name.value().to_ascii_lowercase();
|
||||||
|
let name = name.trim_matches(HTML_SPACE_CHARACTERS);
|
||||||
|
|
||||||
|
match name {
|
||||||
|
"viewport" => self.translate_viewport(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn translate_viewport(&self) {
|
||||||
|
let element = ElementCast::from_ref(self);
|
||||||
|
if let Some(content) = element.get_attribute(&ns!(""), &atom!("content")).r() {
|
||||||
|
let content = content.value();
|
||||||
|
if !content.is_empty() {
|
||||||
|
if let Some(translated_rule) = ViewportRule::from_meta(&**content) {
|
||||||
|
let node = NodeCast::from_ref(self);
|
||||||
|
let win = window_from_node(node);
|
||||||
|
let LayoutChan(ref layout_chan) = win.r().layout_chan();
|
||||||
|
|
||||||
|
layout_chan.send(Msg::AddMetaViewport(translated_rule)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLMetaElementMethods for HTMLMetaElement {
|
impl HTMLMetaElementMethods for HTMLMetaElement {
|
||||||
|
@ -57,3 +91,20 @@ impl HTMLMetaElementMethods for HTMLMetaElement {
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-meta-content
|
// https://html.spec.whatwg.org/multipage/#dom-meta-content
|
||||||
make_setter!(SetContent, "content");
|
make_setter!(SetContent, "content");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VirtualMethods for HTMLMetaElement {
|
||||||
|
fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> {
|
||||||
|
let htmlelement: &HTMLElement = HTMLElementCast::from_ref(self);
|
||||||
|
Some(htmlelement as &VirtualMethods)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_to_tree(&self, tree_in_doc: bool) {
|
||||||
|
if let Some(ref s) = self.super_type() {
|
||||||
|
s.bind_to_tree(tree_in_doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if tree_in_doc {
|
||||||
|
self.process_attributes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ use dom::bindings::codegen::InheritTypes::HTMLIFrameElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLImageElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLImageElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLInputElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLInputElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLLinkElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLLinkElementCast;
|
||||||
|
use dom::bindings::codegen::InheritTypes::HTMLMetaElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLObjectElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLObjectElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLOptGroupElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLOptGroupElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLOptionElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLOptionElementCast;
|
||||||
|
@ -179,6 +180,10 @@ pub fn vtable_for<'a>(node: &'a Node) -> &'a (VirtualMethods + 'a) {
|
||||||
let element = HTMLLinkElementCast::to_ref(node).unwrap();
|
let element = HTMLLinkElementCast::to_ref(node).unwrap();
|
||||||
element as &'a (VirtualMethods + 'a)
|
element as &'a (VirtualMethods + 'a)
|
||||||
}
|
}
|
||||||
|
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMetaElement)) => {
|
||||||
|
let element = HTMLMetaElementCast::to_ref(node).unwrap();
|
||||||
|
element as &'a (VirtualMethods + 'a)
|
||||||
|
}
|
||||||
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement)) => {
|
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement)) => {
|
||||||
let element = HTMLObjectElementCast::to_ref(node).unwrap();
|
let element = HTMLObjectElementCast::to_ref(node).unwrap();
|
||||||
element as &'a (VirtualMethods + 'a)
|
element as &'a (VirtualMethods + 'a)
|
||||||
|
|
|
@ -28,6 +28,7 @@ use string_cache::Atom;
|
||||||
use style::animation::PropertyAnimation;
|
use style::animation::PropertyAnimation;
|
||||||
use style::media_queries::MediaQueryList;
|
use style::media_queries::MediaQueryList;
|
||||||
use style::stylesheets::Stylesheet;
|
use style::stylesheets::Stylesheet;
|
||||||
|
use style::viewport::ViewportRule;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
pub use dom::node::TrustedNodeAddress;
|
pub use dom::node::TrustedNodeAddress;
|
||||||
|
|
||||||
|
@ -39,6 +40,9 @@ pub enum Msg {
|
||||||
/// Adds the given stylesheet to the document.
|
/// Adds the given stylesheet to the document.
|
||||||
LoadStylesheet(Url, MediaQueryList, PendingAsyncLoad, Box<StylesheetLoadResponder + Send>),
|
LoadStylesheet(Url, MediaQueryList, PendingAsyncLoad, Box<StylesheetLoadResponder + Send>),
|
||||||
|
|
||||||
|
/// Adds a @viewport rule (translated from a <META name="viewport"> element) to the document.
|
||||||
|
AddMetaViewport(ViewportRule),
|
||||||
|
|
||||||
/// Puts a document into quirks mode, causing the quirks mode stylesheet to be loaded.
|
/// Puts a document into quirks mode, causing the quirks mode stylesheet to be loaded.
|
||||||
SetQuirksMode,
|
SetQuirksMode,
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
|
use cssparser::ToCss;
|
||||||
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
|
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
|
||||||
use euclid::scale_factor::ScaleFactor;
|
use euclid::scale_factor::ScaleFactor;
|
||||||
use euclid::size::{Size2D, TypedSize2D};
|
use euclid::size::{Size2D, TypedSize2D};
|
||||||
|
@ -10,20 +11,23 @@ use parser::{ParserContext, log_css_error};
|
||||||
use properties::longhands;
|
use properties::longhands;
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::collections::hash_map::{Entry, HashMap};
|
use std::collections::hash_map::{Entry, HashMap};
|
||||||
|
use std::fmt;
|
||||||
use std::intrinsics;
|
use std::intrinsics;
|
||||||
|
use std::iter::Enumerate;
|
||||||
|
use std::str::Chars;
|
||||||
use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom};
|
use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom};
|
||||||
use stylesheets::Origin;
|
use stylesheets::Origin;
|
||||||
use util::geometry::ViewportPx;
|
use util::geometry::ViewportPx;
|
||||||
use values::computed::{Context, ToComputedValue};
|
use values::computed::{Context, ToComputedValue};
|
||||||
use values::specified::LengthOrPercentageOrAuto;
|
use values::specified::{Length, LengthOrPercentageOrAuto, ViewportPercentageLength};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub enum ViewportDescriptor {
|
pub enum ViewportDescriptor {
|
||||||
MinWidth(LengthOrPercentageOrAuto),
|
MinWidth(ViewportLength),
|
||||||
MaxWidth(LengthOrPercentageOrAuto),
|
MaxWidth(ViewportLength),
|
||||||
|
|
||||||
MinHeight(LengthOrPercentageOrAuto),
|
MinHeight(ViewportLength),
|
||||||
MaxHeight(LengthOrPercentageOrAuto),
|
MaxHeight(ViewportLength),
|
||||||
|
|
||||||
Zoom(Zoom),
|
Zoom(Zoom),
|
||||||
MinZoom(Zoom),
|
MinZoom(Zoom),
|
||||||
|
@ -33,6 +37,98 @@ pub enum ViewportDescriptor {
|
||||||
Orientation(Orientation)
|
Orientation(Orientation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait FromMeta: Sized {
|
||||||
|
fn from_meta<'a>(value: &'a 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
|
||||||
|
#[derive(Copy, Clone, Debug, HeapSizeOf, PartialEq)]
|
||||||
|
pub enum ViewportLength {
|
||||||
|
Specified(LengthOrPercentageOrAuto),
|
||||||
|
ExtendToZoom
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for ViewportLength {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||||
|
where W: fmt::Write
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
ViewportLength::Specified(length) => length.to_css(dest),
|
||||||
|
ViewportLength::ExtendToZoom => write!(dest, "extend-to-zoom"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromMeta for ViewportLength {
|
||||||
|
fn from_meta<'a>(value: &'a str) -> Option<ViewportLength> {
|
||||||
|
macro_rules! specified {
|
||||||
|
($value:expr) => {
|
||||||
|
ViewportLength::Specified(LengthOrPercentageOrAuto::Length($value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(match value {
|
||||||
|
v if v.eq_ignore_ascii_case("device-width") =>
|
||||||
|
specified!(Length::ViewportPercentage(ViewportPercentageLength::Vw(100.))),
|
||||||
|
v if v.eq_ignore_ascii_case("device-height") =>
|
||||||
|
specified!(Length::ViewportPercentage(ViewportPercentageLength::Vh(100.))),
|
||||||
|
_ => {
|
||||||
|
match value.parse::<f32>() {
|
||||||
|
Ok(n) if n >= 0. => specified!(Length::from_px(n.max(1.).min(10000.))),
|
||||||
|
Ok(_) => return None,
|
||||||
|
Err(_) => specified!(Length::from_px(1.))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViewportLength {
|
||||||
|
fn parse(input: &mut Parser) -> Result<ViewportLength, ()> {
|
||||||
|
// we explicitly do not accept 'extend-to-zoom', since it is a UA internal value
|
||||||
|
// for <META> viewport translation
|
||||||
|
LengthOrPercentageOrAuto::parse_non_negative(input).map(ViewportLength::Specified)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromMeta for Zoom {
|
||||||
|
fn from_meta<'a>(value: &'a 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<'a>(value: &'a 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> {
|
struct ViewportRuleParser<'a, 'b: 'a> {
|
||||||
context: &'a ParserContext<'b>
|
context: &'a ParserContext<'b>
|
||||||
}
|
}
|
||||||
|
@ -57,10 +153,10 @@ impl ViewportDescriptorDeclaration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_shorthand(input: &mut Parser) -> Result<[LengthOrPercentageOrAuto; 2], ()> {
|
fn parse_shorthand(input: &mut Parser) -> Result<[ViewportLength; 2], ()> {
|
||||||
let min = try!(LengthOrPercentageOrAuto::parse_non_negative(input));
|
let min = try!(ViewportLength::parse(input));
|
||||||
match input.try(|input| LengthOrPercentageOrAuto::parse_non_negative(input)) {
|
match input.try(|input| ViewportLength::parse(input)) {
|
||||||
Err(()) => Ok([min.clone(), min]),
|
Err(()) => Ok([min, min]),
|
||||||
Ok(max) => Ok([min, max])
|
Ok(max) => Ok([min, max])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,16 +198,16 @@ impl<'a, 'b> DeclarationParser for ViewportRuleParser<'a, 'b> {
|
||||||
|
|
||||||
match name {
|
match name {
|
||||||
n if n.eq_ignore_ascii_case("min-width") =>
|
n if n.eq_ignore_ascii_case("min-width") =>
|
||||||
ok!(MinWidth(LengthOrPercentageOrAuto::parse_non_negative)),
|
ok!(MinWidth(ViewportLength::parse)),
|
||||||
n if n.eq_ignore_ascii_case("max-width") =>
|
n if n.eq_ignore_ascii_case("max-width") =>
|
||||||
ok!(MaxWidth(LengthOrPercentageOrAuto::parse_non_negative)),
|
ok!(MaxWidth(ViewportLength::parse)),
|
||||||
n if n.eq_ignore_ascii_case("width") =>
|
n if n.eq_ignore_ascii_case("width") =>
|
||||||
ok!(shorthand -> [MinWidth, MaxWidth]),
|
ok!(shorthand -> [MinWidth, MaxWidth]),
|
||||||
|
|
||||||
n if n.eq_ignore_ascii_case("min-height") =>
|
n if n.eq_ignore_ascii_case("min-height") =>
|
||||||
ok!(MinHeight(LengthOrPercentageOrAuto::parse_non_negative)),
|
ok!(MinHeight(ViewportLength::parse)),
|
||||||
n if n.eq_ignore_ascii_case("max-height") =>
|
n if n.eq_ignore_ascii_case("max-height") =>
|
||||||
ok!(MaxHeight(LengthOrPercentageOrAuto::parse_non_negative)),
|
ok!(MaxHeight(ViewportLength::parse)),
|
||||||
n if n.eq_ignore_ascii_case("height") =>
|
n if n.eq_ignore_ascii_case("height") =>
|
||||||
ok!(shorthand -> [MinHeight, MaxHeight]),
|
ok!(shorthand -> [MinHeight, MaxHeight]),
|
||||||
|
|
||||||
|
@ -137,6 +233,19 @@ pub struct ViewportRule {
|
||||||
pub declarations: Vec<ViewportDescriptorDeclaration>
|
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 {
|
impl ViewportRule {
|
||||||
pub fn parse(input: &mut Parser, context: &ParserContext)
|
pub fn parse(input: &mut Parser, context: &ParserContext)
|
||||||
-> Result<ViewportRule, ()>
|
-> Result<ViewportRule, ()>
|
||||||
|
@ -166,6 +275,145 @@ impl ViewportRule {
|
||||||
|
|
||||||
Ok(ViewportRule { declarations: valid_declarations.iter().cascade() })
|
Ok(ViewportRule { declarations: valid_declarations.iter().cascade() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_meta<'a>(content: &'a str) -> Option<ViewportRule> {
|
||||||
|
let mut declarations = HashMap::new();
|
||||||
|
macro_rules! push_descriptor {
|
||||||
|
($descriptor:ident($value:expr)) => {{
|
||||||
|
let descriptor = ViewportDescriptor::$descriptor($value);
|
||||||
|
declarations.insert(
|
||||||
|
unsafe {
|
||||||
|
intrinsics::discriminant_value(&descriptor)
|
||||||
|
},
|
||||||
|
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(LengthOrPercentageOrAuto::Auto)));
|
||||||
|
push_descriptor!(MaxWidth(ViewportLength::Specified(LengthOrPercentageOrAuto::Auto)));
|
||||||
|
} else {
|
||||||
|
push_descriptor!(MinWidth(ViewportLength::ExtendToZoom));
|
||||||
|
push_descriptor!(MaxWidth(ViewportLength::ExtendToZoom));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let declarations: Vec<_> = declarations.into_iter().map(|kv| kv.1).collect();
|
||||||
|
if !declarations.is_empty() {
|
||||||
|
Some(ViewportRule { declarations: 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<'a>(iter: &mut Enumerate<Chars<'a>>) -> Option<(usize, char)> {
|
||||||
|
iter.by_ref()
|
||||||
|
.skip_while(|&(_, c)| !is_whitespace_separator_or_equals(&c))
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_whitespace<'a>(iter: &mut Enumerate<Chars<'a>>) -> 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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ViewportRuleCascade: Iterator + Sized {
|
pub trait ViewportRuleCascade: Iterator + Sized {
|
||||||
|
@ -306,9 +554,9 @@ impl MaybeNew for ViewportConstraints {
|
||||||
($op:ident, $opta:expr, $optb:expr) => {
|
($op:ident, $opta:expr, $optb:expr) => {
|
||||||
match ($opta, $optb) {
|
match ($opta, $optb) {
|
||||||
(None, None) => None,
|
(None, None) => None,
|
||||||
(a, None) => a.clone(),
|
(a, None) => a,
|
||||||
(None, b) => b.clone(),
|
(None, b) => b,
|
||||||
(a, b) => Some(a.clone().unwrap().$op(b.clone().unwrap())),
|
(a, b) => Some(a.unwrap().$op(b.unwrap())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,7 +573,7 @@ impl MaybeNew for ViewportConstraints {
|
||||||
|
|
||||||
// DEVICE-ADAPT § 6.2.1 Resolve min-zoom and max-zoom values
|
// DEVICE-ADAPT § 6.2.1 Resolve min-zoom and max-zoom values
|
||||||
if min_zoom.is_some() && max_zoom.is_some() {
|
if min_zoom.is_some() && max_zoom.is_some() {
|
||||||
max_zoom = Some(min_zoom.clone().unwrap().max(max_zoom.unwrap()))
|
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
|
// DEVICE-ADAPT § 6.2.2 Constrain zoom value to the [min-zoom, max-zoom] range
|
||||||
|
@ -363,18 +611,41 @@ impl MaybeNew for ViewportConstraints {
|
||||||
outline_style_present: false,
|
outline_style_present: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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 {
|
macro_rules! to_pixel_length {
|
||||||
($value:ident, $dimension:ident) => {
|
($value:ident, $dimension:ident, $extend_to:ident => $auto_extend_to:expr) => {
|
||||||
if let Some($value) = $value {
|
if let Some($value) = $value {
|
||||||
match $value {
|
match $value {
|
||||||
LengthOrPercentageOrAuto::Length(value) =>
|
ViewportLength::Specified(length) => match length {
|
||||||
Some(value.to_computed_value(&context)),
|
LengthOrPercentageOrAuto::Length(value) =>
|
||||||
LengthOrPercentageOrAuto::Percentage(value) =>
|
Some(value.to_computed_value(&context)),
|
||||||
Some(initial_viewport.$dimension.scale_by(value.0)),
|
LengthOrPercentageOrAuto::Percentage(value) =>
|
||||||
LengthOrPercentageOrAuto::Auto => None,
|
Some(initial_viewport.$dimension.scale_by(value.0)),
|
||||||
LengthOrPercentageOrAuto::Calc(calc) => {
|
LengthOrPercentageOrAuto::Auto => None,
|
||||||
let calc = calc.to_computed_value(&context);
|
LengthOrPercentageOrAuto::Calc(calc) => {
|
||||||
Some(initial_viewport.$dimension.scale_by(calc.percentage()) + calc.length())
|
let calc = calc.to_computed_value(&context);
|
||||||
|
Some(initial_viewport.$dimension.scale_by(calc.percentage()) + calc.length())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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 {
|
} else {
|
||||||
|
@ -383,10 +654,14 @@ impl MaybeNew for ViewportConstraints {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let min_width = to_pixel_length!(min_width, width);
|
// DEVICE-ADAPT § 9.3 states that max-descriptors need to be resolved
|
||||||
let max_width = to_pixel_length!(max_width, width);
|
// before min-descriptors.
|
||||||
let min_height = to_pixel_length!(min_height, height);
|
// http://dev.w3.org/csswg/css-device-adapt/#resolve-extend-to-zoom
|
||||||
let max_height = to_pixel_length!(max_height, height);
|
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
|
// DEVICE-ADAPT § 6.2.4 Resolve initial width and height from min/max descriptors
|
||||||
macro_rules! resolve {
|
macro_rules! resolve {
|
||||||
|
@ -421,7 +696,7 @@ impl MaybeNew for ViewportConstraints {
|
||||||
Au(0) => initial_viewport.width,
|
Au(0) => initial_viewport.width,
|
||||||
initial_height => {
|
initial_height => {
|
||||||
let ratio = initial_viewport.width.to_f32_px() / initial_height.to_f32_px();
|
let ratio = initial_viewport.width.to_f32_px() / initial_height.to_f32_px();
|
||||||
Au::from_f32_px(height.clone().unwrap().to_f32_px() * ratio)
|
Au::from_f32_px(height.unwrap().to_f32_px() * ratio)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -397,6 +397,7 @@ flaky_cpu,prefs:"layout.writing-mode.enabled" == vertical-lr-blocks.html vertica
|
||||||
== vertical_align_top_a.html vertical_align_top_ref.html
|
== vertical_align_top_a.html vertical_align_top_ref.html
|
||||||
== vertical_align_top_bottom_a.html vertical_align_top_bottom_ref.html
|
== vertical_align_top_bottom_a.html vertical_align_top_bottom_ref.html
|
||||||
== vertical_align_top_span_a.html vertical_align_top_span_ref.html
|
== vertical_align_top_span_a.html vertical_align_top_span_ref.html
|
||||||
|
== viewport_meta.html viewport_rule_ref.html
|
||||||
resolution=800x600 == viewport_percentage_vmin_vmax.html viewport_percentage_vmin_vmax_a.html
|
resolution=800x600 == viewport_percentage_vmin_vmax.html viewport_percentage_vmin_vmax_a.html
|
||||||
# resolution=600x800 == viewport_percentage_vmin_vmax.html viewport_percentage_vmin_vmax_b.html
|
# resolution=600x800 == viewport_percentage_vmin_vmax.html viewport_percentage_vmin_vmax_b.html
|
||||||
resolution=800x600 == viewport_percentage_vw_vh.html viewport_percentage_vw_vh_a.html
|
resolution=800x600 == viewport_percentage_vw_vh.html viewport_percentage_vw_vh_a.html
|
||||||
|
|
25
tests/ref/viewport_meta.html
Normal file
25
tests/ref/viewport_meta.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=240">
|
||||||
|
<style>
|
||||||
|
#container {
|
||||||
|
background: blue;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
#box {
|
||||||
|
background: green;
|
||||||
|
height: 50vh;
|
||||||
|
width: 50vw;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
<div id="box">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#![feature(plugin)]
|
#![feature(plugin)]
|
||||||
|
#![cfg_attr(test, feature(core_intrinsics))]
|
||||||
#![plugin(string_cache_plugin)]
|
#![plugin(string_cache_plugin)]
|
||||||
|
|
||||||
extern crate app_units;
|
extern crate app_units;
|
||||||
|
|
|
@ -8,7 +8,9 @@ use euclid::size::Size2D;
|
||||||
use style::media_queries::{Device, MediaType};
|
use style::media_queries::{Device, MediaType};
|
||||||
use style::parser::ParserContext;
|
use style::parser::ParserContext;
|
||||||
use style::stylesheets::{Origin, Stylesheet, CSSRuleIteratorExt};
|
use style::stylesheets::{Origin, Stylesheet, CSSRuleIteratorExt};
|
||||||
use style::values::specified::{Length, LengthOrPercentageOrAuto};
|
use style::values::specified::Length::{self, ViewportPercentage};
|
||||||
|
use style::values::specified::LengthOrPercentageOrAuto::{self, Auto};
|
||||||
|
use style::values::specified::ViewportPercentageLength::Vw;
|
||||||
use style::viewport::*;
|
use style::viewport::*;
|
||||||
use style_traits::viewport::*;
|
use style_traits::viewport::*;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -38,6 +40,26 @@ fn test_viewport_rule<F>(css: &str,
|
||||||
assert!(rule_count > 0);
|
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) {
|
||||||
|
use std::intrinsics::discriminant_value;
|
||||||
|
|
||||||
|
// 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 = unsafe { discriminant_value(&a.descriptor) };
|
||||||
|
let b = unsafe { discriminant_value(&b.descriptor) };
|
||||||
|
a.cmp(&b)
|
||||||
|
});
|
||||||
|
|
||||||
|
callback(&rule.declarations, meta);
|
||||||
|
} else {
|
||||||
|
panic!("no @viewport rule for {}", meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! assert_decl_len {
|
macro_rules! assert_decl_len {
|
||||||
($declarations:ident == 1) => {
|
($declarations:ident == 1) => {
|
||||||
assert!($declarations.len() == 1,
|
assert!($declarations.len() == 1,
|
||||||
|
@ -51,6 +73,15 @@ macro_rules! assert_decl_len {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! viewport_length {
|
||||||
|
($value:expr, px) => {
|
||||||
|
ViewportLength::Specified(LengthOrPercentageOrAuto::Length(Length::from_px($value)))
|
||||||
|
};
|
||||||
|
($value:expr, vw) => {
|
||||||
|
ViewportLength::Specified(LengthOrPercentageOrAuto::Length(ViewportPercentage(Vw($value))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_viewport_rule() {
|
fn empty_viewport_rule() {
|
||||||
let device = Device::new(MediaType::Screen, Size2D::typed(800., 600.));
|
let device = Device::new(MediaType::Screen, Size2D::typed(800., 600.));
|
||||||
|
@ -84,10 +115,10 @@ fn simple_viewport_rules() {
|
||||||
&device, |declarations, css| {
|
&device, |declarations, css| {
|
||||||
println!("{}", css);
|
println!("{}", css);
|
||||||
assert_decl_len!(declarations == 9);
|
assert_decl_len!(declarations == 9);
|
||||||
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto);
|
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto));
|
||||||
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Auto);
|
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto));
|
||||||
assert_decl_eq!(&declarations[2], Author, MinHeight: LengthOrPercentageOrAuto::Auto);
|
assert_decl_eq!(&declarations[2], Author, MinHeight: ViewportLength::Specified(Auto));
|
||||||
assert_decl_eq!(&declarations[3], Author, MaxHeight: LengthOrPercentageOrAuto::Auto);
|
assert_decl_eq!(&declarations[3], Author, MaxHeight: ViewportLength::Specified(Auto));
|
||||||
assert_decl_eq!(&declarations[4], Author, Zoom: Zoom::Auto);
|
assert_decl_eq!(&declarations[4], Author, Zoom: Zoom::Auto);
|
||||||
assert_decl_eq!(&declarations[5], Author, MinZoom: Zoom::Number(0.));
|
assert_decl_eq!(&declarations[5], Author, MinZoom: Zoom::Number(0.));
|
||||||
assert_decl_eq!(&declarations[6], Author, MaxZoom: Zoom::Percentage(2.));
|
assert_decl_eq!(&declarations[6], Author, MaxZoom: Zoom::Percentage(2.));
|
||||||
|
@ -100,10 +131,49 @@ fn simple_viewport_rules() {
|
||||||
&device, |declarations, css| {
|
&device, |declarations, css| {
|
||||||
println!("{}", css);
|
println!("{}", css);
|
||||||
assert_decl_len!(declarations == 4);
|
assert_decl_len!(declarations == 4);
|
||||||
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Length(Length::from_px(200.)));
|
assert_decl_eq!(&declarations[0], Author, MinWidth: viewport_length!(200., px));
|
||||||
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Auto);
|
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto));
|
||||||
assert_decl_eq!(&declarations[2], Author, MinHeight: LengthOrPercentageOrAuto::Length(Length::from_px(200.)));
|
assert_decl_eq!(&declarations[2], Author, MinHeight: viewport_length!(200., px));
|
||||||
assert_decl_eq!(&declarations[3], Author, MaxHeight: LengthOrPercentageOrAuto::Auto);
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +186,7 @@ fn cascading_within_viewport_rule() {
|
||||||
&device, |declarations, css| {
|
&device, |declarations, css| {
|
||||||
println!("{}", css);
|
println!("{}", css);
|
||||||
assert_decl_len!(declarations == 1);
|
assert_decl_len!(declarations == 1);
|
||||||
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto);
|
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto));
|
||||||
});
|
});
|
||||||
|
|
||||||
// !important order of appearance
|
// !important order of appearance
|
||||||
|
@ -124,7 +194,7 @@ fn cascading_within_viewport_rule() {
|
||||||
&device, |declarations, css| {
|
&device, |declarations, css| {
|
||||||
println!("{}", css);
|
println!("{}", css);
|
||||||
assert_decl_len!(declarations == 1);
|
assert_decl_len!(declarations == 1);
|
||||||
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto, !important);
|
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto), !important);
|
||||||
});
|
});
|
||||||
|
|
||||||
// !important vs normal
|
// !important vs normal
|
||||||
|
@ -132,7 +202,7 @@ fn cascading_within_viewport_rule() {
|
||||||
&device, |declarations, css| {
|
&device, |declarations, css| {
|
||||||
println!("{}", css);
|
println!("{}", css);
|
||||||
assert_decl_len!(declarations == 1);
|
assert_decl_len!(declarations == 1);
|
||||||
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto, !important);
|
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto), !important);
|
||||||
});
|
});
|
||||||
|
|
||||||
// normal longhands vs normal shorthand
|
// normal longhands vs normal shorthand
|
||||||
|
@ -140,8 +210,8 @@ fn cascading_within_viewport_rule() {
|
||||||
&device, |declarations, css| {
|
&device, |declarations, css| {
|
||||||
println!("{}", css);
|
println!("{}", css);
|
||||||
assert_decl_len!(declarations == 2);
|
assert_decl_len!(declarations == 2);
|
||||||
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto);
|
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto));
|
||||||
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Auto);
|
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto));
|
||||||
});
|
});
|
||||||
|
|
||||||
// normal shorthand vs normal longhands
|
// normal shorthand vs normal longhands
|
||||||
|
@ -149,8 +219,8 @@ fn cascading_within_viewport_rule() {
|
||||||
&device, |declarations, css| {
|
&device, |declarations, css| {
|
||||||
println!("{}", css);
|
println!("{}", css);
|
||||||
assert_decl_len!(declarations == 2);
|
assert_decl_len!(declarations == 2);
|
||||||
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto);
|
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto));
|
||||||
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Auto);
|
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto));
|
||||||
});
|
});
|
||||||
|
|
||||||
// one !important longhand vs normal shorthand
|
// one !important longhand vs normal shorthand
|
||||||
|
@ -158,8 +228,8 @@ fn cascading_within_viewport_rule() {
|
||||||
&device, |declarations, css| {
|
&device, |declarations, css| {
|
||||||
println!("{}", css);
|
println!("{}", css);
|
||||||
assert_decl_len!(declarations == 2);
|
assert_decl_len!(declarations == 2);
|
||||||
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto, !important);
|
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto), !important);
|
||||||
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Length(Length::from_px(200.)));
|
assert_decl_eq!(&declarations[1], Author, MaxWidth: viewport_length!(200., px));
|
||||||
});
|
});
|
||||||
|
|
||||||
// both !important longhands vs normal shorthand
|
// both !important longhands vs normal shorthand
|
||||||
|
@ -167,8 +237,8 @@ fn cascading_within_viewport_rule() {
|
||||||
&device, |declarations, css| {
|
&device, |declarations, css| {
|
||||||
println!("{}", css);
|
println!("{}", css);
|
||||||
assert_decl_len!(declarations == 2);
|
assert_decl_len!(declarations == 2);
|
||||||
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto, !important);
|
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto), !important);
|
||||||
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Auto, !important);
|
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto), !important);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,8 +259,8 @@ fn multiple_stylesheets_cascading() {
|
||||||
.declarations;
|
.declarations;
|
||||||
assert_decl_len!(declarations == 3);
|
assert_decl_len!(declarations == 3);
|
||||||
assert_decl_eq!(&declarations[0], UserAgent, Zoom: Zoom::Number(1.));
|
assert_decl_eq!(&declarations[0], UserAgent, Zoom: Zoom::Number(1.));
|
||||||
assert_decl_eq!(&declarations[1], User, MinHeight: LengthOrPercentageOrAuto::Length(Length::from_px(200.)));
|
assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px));
|
||||||
assert_decl_eq!(&declarations[2], Author, MinWidth: LengthOrPercentageOrAuto::Length(Length::from_px(300.)));
|
assert_decl_eq!(&declarations[2], Author, MinWidth: viewport_length!(300., px));
|
||||||
|
|
||||||
let stylesheets = vec![
|
let stylesheets = vec![
|
||||||
stylesheet!("@viewport { min-width: 100px !important; }", UserAgent),
|
stylesheet!("@viewport { min-width: 100px !important; }", UserAgent),
|
||||||
|
@ -203,10 +273,8 @@ fn multiple_stylesheets_cascading() {
|
||||||
.cascade()
|
.cascade()
|
||||||
.declarations;
|
.declarations;
|
||||||
assert_decl_len!(declarations == 3);
|
assert_decl_len!(declarations == 3);
|
||||||
assert_decl_eq!(
|
assert_decl_eq!(&declarations[0], UserAgent, MinWidth: viewport_length!(100., px), !important);
|
||||||
&declarations[0], UserAgent, MinWidth: LengthOrPercentageOrAuto::Length(Length::from_px(100.)), !important);
|
assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px), !important);
|
||||||
assert_decl_eq!(
|
|
||||||
&declarations[1], User, MinHeight: LengthOrPercentageOrAuto::Length(Length::from_px(200.)), !important);
|
|
||||||
assert_decl_eq!(&declarations[2], Author, Zoom: Zoom::Number(3.), !important);
|
assert_decl_eq!(&declarations[2], Author, Zoom: Zoom::Number(3.), !important);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue