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:
bors-servo 2015-09-30 22:49:41 -06:00
commit a7743052ca
9 changed files with 508 additions and 62 deletions

View file

@ -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_bottom_a.html vertical_align_top_bottom_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=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

View 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>

View file

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![feature(plugin)]
#![cfg_attr(test, feature(core_intrinsics))]
#![plugin(string_cache_plugin)]
extern crate app_units;

View file

@ -8,7 +8,9 @@ use euclid::size::Size2D;
use style::media_queries::{Device, MediaType};
use style::parser::ParserContext;
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_traits::viewport::*;
use url::Url;
@ -38,6 +40,26 @@ fn test_viewport_rule<F>(css: &str,
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 {
($declarations:ident == 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]
fn empty_viewport_rule() {
let device = Device::new(MediaType::Screen, Size2D::typed(800., 600.));
@ -84,10 +115,10 @@ fn simple_viewport_rules() {
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 9);
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto);
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Auto);
assert_decl_eq!(&declarations[2], Author, MinHeight: LengthOrPercentageOrAuto::Auto);
assert_decl_eq!(&declarations[3], Author, MaxHeight: LengthOrPercentageOrAuto::Auto);
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.));
@ -100,10 +131,49 @@ fn simple_viewport_rules() {
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 4);
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Length(Length::from_px(200.)));
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Auto);
assert_decl_eq!(&declarations[2], Author, MinHeight: LengthOrPercentageOrAuto::Length(Length::from_px(200.)));
assert_decl_eq!(&declarations[3], Author, MaxHeight: LengthOrPercentageOrAuto::Auto);
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);
});
}
@ -116,7 +186,7 @@ fn cascading_within_viewport_rule() {
&device, |declarations, css| {
println!("{}", css);
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
@ -124,7 +194,7 @@ fn cascading_within_viewport_rule() {
&device, |declarations, css| {
println!("{}", css);
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
@ -132,7 +202,7 @@ fn cascading_within_viewport_rule() {
&device, |declarations, css| {
println!("{}", css);
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
@ -140,8 +210,8 @@ fn cascading_within_viewport_rule() {
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 2);
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto);
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Auto);
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
@ -149,8 +219,8 @@ fn cascading_within_viewport_rule() {
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 2);
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto);
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Auto);
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
@ -158,8 +228,8 @@ fn cascading_within_viewport_rule() {
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 2);
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto, !important);
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Length(Length::from_px(200.)));
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
@ -167,8 +237,8 @@ fn cascading_within_viewport_rule() {
&device, |declarations, css| {
println!("{}", css);
assert_decl_len!(declarations == 2);
assert_decl_eq!(&declarations[0], Author, MinWidth: LengthOrPercentageOrAuto::Auto, !important);
assert_decl_eq!(&declarations[1], Author, MaxWidth: LengthOrPercentageOrAuto::Auto, !important);
assert_decl_eq!(&declarations[0], Author, MinWidth: ViewportLength::Specified(Auto), !important);
assert_decl_eq!(&declarations[1], Author, MaxWidth: ViewportLength::Specified(Auto), !important);
});
}
@ -189,8 +259,8 @@ fn multiple_stylesheets_cascading() {
.declarations;
assert_decl_len!(declarations == 3);
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[2], Author, MinWidth: LengthOrPercentageOrAuto::Length(Length::from_px(300.)));
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),
@ -203,10 +273,8 @@ fn multiple_stylesheets_cascading() {
.cascade()
.declarations;
assert_decl_len!(declarations == 3);
assert_decl_eq!(
&declarations[0], UserAgent, MinWidth: LengthOrPercentageOrAuto::Length(Length::from_px(100.)), !important);
assert_decl_eq!(
&declarations[1], User, MinHeight: LengthOrPercentageOrAuto::Length(Length::from_px(200.)), !important);
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);
}